1 Objetivo

Considere el dataset proporcionado que contiene información sobre distintos sensores corporales y cuyo objetivo es predecir la postura corporal durante la realización de un ejercicio. Los distintos tipos de posturas están codificados en una variable llamada classe con las letras de la A a la E, representando, respectivamente:

  • A: postura correcta en la realización del ejercicio.
  • B-E: distintos errores típicos durante la realización del ejercicio.

Como vamos a tratar el problema como uno de aprendizaje no supervisado, es conveniente asegurarse de no incluir el atributo de clase entre las características con las que se entrene el modelo

El ejercicio consiste, por tanto, en construir un modelo de segmentación que intente capturar la estructura de grupos existente en el conjunto de datos original.

Se sugiere un rápido análisis exploratorio del conjunto de datos para determinar si:

  • Existen variables que haya que descartar por ser identificadores (o asimilables a identificadores) o que no aporten información útil para resolver el problema.
  • Existen variables con demasiados valores nulos como para poder ser utilizadas.
  • Existen variables con valores en distintos órdenes de magnitud, circunstancia que podría afectar al rendimiento de determinados modelos.

Aparte de lo anterior, conviene explorar la posibilidad de usar distintos modelos de aprendizaje, que pueden ser comparados de acuerdo con alguna métrica de calidad. En este caso, y dado que se dispone de las etiquetas reales de los datos, se podría usar una métrica de evaluación externa. En cualquier caso, y al tratarse de un conjunto de datos de un volumen no despreciable, se recomienda cuidado al calcular muchas métricas de evaluación, ya que algunas pueden tardar mucho tiempo en calcularse. Con el objetivo de cubrir el proceso total de análisis de un problema de estas características, se recomienda calcular sólo una o dos, aunque en un escenario real, tal y como vimos en clase, podría ser recomendable calcular más.

2 Importación de librerías y datos

2.1 Librerías

library(corrplot) # Matriz de correlaciones
library(clusterSim)
library(tidyverse) # Cargo tidyverse después de clusterSim porque el paquete Mass de clusterSim masks 'dplyr::select()'

library(fpc)
library(factoextra)
library(NbClust)
library(caret)
library(cluster)
library(mclust)
library(dbscan)

library(ggplot2)
library(plotly)

2.2 Datos

Importamos los datos y visualizamos una muestra.

df <- read_csv("../data/datos_train.csv")
knitr::kable(head(df))
user_name raw_timestamp_part_1 raw_timestamp_part_2 cvtd_timestamp roll_belt pitch_belt yaw_belt total_accel_belt kurtosis_roll_belt kurtosis_picth_belt kurtosis_yaw_belt skewness_roll_belt skewness_roll_belt.1 skewness_yaw_belt max_roll_belt max_picth_belt max_yaw_belt min_roll_belt min_pitch_belt min_yaw_belt amplitude_roll_belt amplitude_pitch_belt amplitude_yaw_belt var_total_accel_belt avg_roll_belt stddev_roll_belt var_roll_belt avg_pitch_belt stddev_pitch_belt var_pitch_belt avg_yaw_belt stddev_yaw_belt var_yaw_belt gyros_belt_x gyros_belt_y gyros_belt_z accel_belt_x accel_belt_y accel_belt_z magnet_belt_x magnet_belt_y magnet_belt_z roll_arm pitch_arm yaw_arm total_accel_arm var_accel_arm avg_roll_arm stddev_roll_arm var_roll_arm avg_pitch_arm stddev_pitch_arm var_pitch_arm avg_yaw_arm stddev_yaw_arm var_yaw_arm gyros_arm_x gyros_arm_y gyros_arm_z accel_arm_x accel_arm_y accel_arm_z magnet_arm_x magnet_arm_y magnet_arm_z kurtosis_roll_arm kurtosis_picth_arm kurtosis_yaw_arm skewness_roll_arm skewness_pitch_arm skewness_yaw_arm max_roll_arm max_picth_arm max_yaw_arm min_roll_arm min_pitch_arm min_yaw_arm amplitude_roll_arm amplitude_pitch_arm amplitude_yaw_arm roll_dumbbell pitch_dumbbell yaw_dumbbell kurtosis_roll_dumbbell kurtosis_picth_dumbbell kurtosis_yaw_dumbbell skewness_roll_dumbbell skewness_pitch_dumbbell skewness_yaw_dumbbell max_roll_dumbbell max_picth_dumbbell max_yaw_dumbbell min_roll_dumbbell min_pitch_dumbbell min_yaw_dumbbell amplitude_roll_dumbbell amplitude_pitch_dumbbell amplitude_yaw_dumbbell total_accel_dumbbell var_accel_dumbbell avg_roll_dumbbell stddev_roll_dumbbell var_roll_dumbbell avg_pitch_dumbbell stddev_pitch_dumbbell var_pitch_dumbbell avg_yaw_dumbbell stddev_yaw_dumbbell var_yaw_dumbbell gyros_dumbbell_x gyros_dumbbell_y gyros_dumbbell_z accel_dumbbell_x accel_dumbbell_y accel_dumbbell_z magnet_dumbbell_x magnet_dumbbell_y magnet_dumbbell_z roll_forearm pitch_forearm yaw_forearm kurtosis_roll_forearm kurtosis_picth_forearm kurtosis_yaw_forearm skewness_roll_forearm skewness_pitch_forearm skewness_yaw_forearm max_roll_forearm max_picth_forearm max_yaw_forearm min_roll_forearm min_pitch_forearm min_yaw_forearm amplitude_roll_forearm amplitude_pitch_forearm amplitude_yaw_forearm total_accel_forearm var_accel_forearm avg_roll_forearm stddev_roll_forearm var_roll_forearm avg_pitch_forearm stddev_pitch_forearm var_pitch_forearm avg_yaw_forearm stddev_yaw_forearm var_yaw_forearm gyros_forearm_x gyros_forearm_y gyros_forearm_z accel_forearm_x accel_forearm_y accel_forearm_z magnet_forearm_x magnet_forearm_y magnet_forearm_z classe
carlitos 1323084231 788290 05/12/2011 11:23 1.41 8.07 -94.4 3 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 0.00 0.00 -0.02 -21 4 22 -3 599 -313 -128 22.5 -161 34 NA NA NA NA NA NA NA NA NA NA 0.00 0.00 -0.02 -288 109 -123 -368 337 516 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 13.05217 -70.49400 -84.87394 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 37 NA NA NA NA NA NA NA NA NA NA 0 -0.02 0.00 -234 47 -271 -559 293 -65 28.4 -63.9 -153 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 36 NA NA NA NA NA NA NA NA NA NA 0.03 0.00 -0.02 192 203 -215 -17 654 476 A
carlitos 1323084231 808298 05/12/2011 11:23 1.41 8.07 -94.4 3 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 0.02 0.00 -0.02 -22 4 22 -7 608 -311 -128 22.5 -161 34 NA NA NA NA NA NA NA NA NA NA 0.02 -0.02 -0.02 -290 110 -125 -369 337 513 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 13.13074 -70.63751 -84.71065 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 37 NA NA NA NA NA NA NA NA NA NA 0 -0.02 0.00 -233 47 -269 -555 296 -64 28.3 -63.9 -153 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 36 NA NA NA NA NA NA NA NA NA NA 0.02 0.00 -0.02 192 203 -216 -18 661 473 A
carlitos 1323084231 820366 05/12/2011 11:23 1.42 8.07 -94.4 3 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 0.00 0.00 -0.02 -20 5 23 -2 600 -305 -128 22.5 -161 34 NA NA NA NA NA NA NA NA NA NA 0.02 -0.02 -0.02 -289 110 -126 -368 344 513 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 12.85075 -70.27812 -85.14078 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 37 NA NA NA NA NA NA NA NA NA NA 0 -0.02 0.00 -232 46 -270 -561 298 -63 28.3 -63.9 -152 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 36 NA NA NA NA NA NA NA NA NA NA 0.03 -0.02 0.00 196 204 -213 -18 658 469 A
carlitos 1323084232 120339 05/12/2011 11:23 1.48 8.05 -94.4 3 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 0.02 0.00 -0.03 -22 3 21 -6 604 -310 -128 22.1 -161 34 NA NA NA NA NA NA NA NA NA NA 0.02 -0.03 0.02 -289 111 -123 -372 344 512 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 13.43120 -70.39379 -84.87363 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 37 NA NA NA NA NA NA NA NA NA NA 0 -0.02 -0.02 -232 48 -269 -552 303 -60 28.1 -63.9 -152 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 36 NA NA NA NA NA NA NA NA NA NA 0.02 -0.02 0.00 189 206 -214 -16 658 469 A
carlitos 1323084232 196328 05/12/2011 11:23 1.48 8.07 -94.4 3 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 0.02 0.02 -0.02 -21 2 24 -6 600 -302 -128 22.1 -161 34 NA NA NA NA NA NA NA NA NA NA 0.00 -0.03 0.00 -289 111 -123 -374 337 506 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 13.37872 -70.42856 -84.85306 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 37 NA NA NA NA NA NA NA NA NA NA 0 -0.02 0.00 -233 48 -270 -554 292 -68 28.0 -63.9 -152 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 36 NA NA NA NA NA NA NA NA NA NA 0.02 0.00 -0.02 189 206 -214 -17 655 473 A
carlitos 1323084232 304277 05/12/2011 11:23 1.45 8.06 -94.4 3 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 0.02 0.00 -0.02 -21 4 21 0 603 -312 -128 22.0 -161 34 NA NA NA NA NA NA NA NA NA NA 0.02 -0.03 0.00 -289 111 -122 -369 342 513 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 13.38246 -70.81759 -84.46500 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 37 NA NA NA NA NA NA NA NA NA NA 0 -0.02 0.00 -234 48 -269 -558 294 -66 27.9 -63.9 -152 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA 36 NA NA NA NA NA NA NA NA NA NA 0.02 -0.02 -0.03 193 203 -215 -9 660 478 A

3 Auditoría de datos

Observamos el tamaño del conjunto de datos y su estructura.

Número de filas (instancias):

nrow(df)
## [1] 19622

Número de columnas (variables):

ncol(df)
## [1] 157

Información y estructura del dataframe

str(df)
## tibble [19,622 x 157] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ user_name               : chr [1:19622] "carlitos" "carlitos" "carlitos" "carlitos" ...
##  $ raw_timestamp_part_1    : num [1:19622] 1.32e+09 1.32e+09 1.32e+09 1.32e+09 1.32e+09 ...
##  $ raw_timestamp_part_2    : num [1:19622] 788290 808298 820366 120339 196328 ...
##  $ cvtd_timestamp          : chr [1:19622] "05/12/2011 11:23" "05/12/2011 11:23" "05/12/2011 11:23" "05/12/2011 11:23" ...
##  $ roll_belt               : num [1:19622] 1.41 1.41 1.42 1.48 1.48 1.45 1.42 1.42 1.43 1.45 ...
##  $ pitch_belt              : num [1:19622] 8.07 8.07 8.07 8.05 8.07 8.06 8.09 8.13 8.16 8.17 ...
##  $ yaw_belt                : num [1:19622] -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 -94.4 ...
##  $ total_accel_belt        : num [1:19622] 3 3 3 3 3 3 3 3 3 3 ...
##  $ kurtosis_roll_belt      : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ kurtosis_picth_belt     : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ kurtosis_yaw_belt       : logi [1:19622] NA NA NA NA NA NA ...
##  $ skewness_roll_belt      : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ skewness_roll_belt.1    : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ skewness_yaw_belt       : logi [1:19622] NA NA NA NA NA NA ...
##  $ max_roll_belt           : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ max_picth_belt          : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ max_yaw_belt            : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ min_roll_belt           : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ min_pitch_belt          : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ min_yaw_belt            : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ amplitude_roll_belt     : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ amplitude_pitch_belt    : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ amplitude_yaw_belt      : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ var_total_accel_belt    : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ avg_roll_belt           : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ stddev_roll_belt        : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ var_roll_belt           : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ avg_pitch_belt          : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ stddev_pitch_belt       : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ var_pitch_belt          : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ avg_yaw_belt            : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ stddev_yaw_belt         : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ var_yaw_belt            : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ gyros_belt_x            : num [1:19622] 0 0.02 0 0.02 0.02 0.02 0.02 0.02 0.02 0.03 ...
##  $ gyros_belt_y            : num [1:19622] 0 0 0 0 0.02 0 0 0 0 0 ...
##  $ gyros_belt_z            : num [1:19622] -0.02 -0.02 -0.02 -0.03 -0.02 -0.02 -0.02 -0.02 -0.02 0 ...
##  $ accel_belt_x            : num [1:19622] -21 -22 -20 -22 -21 -21 -22 -22 -20 -21 ...
##  $ accel_belt_y            : num [1:19622] 4 4 5 3 2 4 3 4 2 4 ...
##  $ accel_belt_z            : num [1:19622] 22 22 23 21 24 21 21 21 24 22 ...
##  $ magnet_belt_x           : num [1:19622] -3 -7 -2 -6 -6 0 -4 -2 1 -3 ...
##  $ magnet_belt_y           : num [1:19622] 599 608 600 604 600 603 599 603 602 609 ...
##  $ magnet_belt_z           : num [1:19622] -313 -311 -305 -310 -302 -312 -311 -313 -312 -308 ...
##  $ roll_arm                : num [1:19622] -128 -128 -128 -128 -128 -128 -128 -128 -128 -128 ...
##  $ pitch_arm               : num [1:19622] 22.5 22.5 22.5 22.1 22.1 22 21.9 21.8 21.7 21.6 ...
##  $ yaw_arm                 : num [1:19622] -161 -161 -161 -161 -161 -161 -161 -161 -161 -161 ...
##  $ total_accel_arm         : num [1:19622] 34 34 34 34 34 34 34 34 34 34 ...
##  $ var_accel_arm           : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ avg_roll_arm            : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ stddev_roll_arm         : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ var_roll_arm            : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ avg_pitch_arm           : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ stddev_pitch_arm        : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ var_pitch_arm           : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ avg_yaw_arm             : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ stddev_yaw_arm          : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ var_yaw_arm             : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ gyros_arm_x             : num [1:19622] 0 0.02 0.02 0.02 0 0.02 0 0.02 0.02 0.02 ...
##  $ gyros_arm_y             : num [1:19622] 0 -0.02 -0.02 -0.03 -0.03 -0.03 -0.03 -0.02 -0.03 -0.03 ...
##  $ gyros_arm_z             : num [1:19622] -0.02 -0.02 -0.02 0.02 0 0 0 0 -0.02 -0.02 ...
##  $ accel_arm_x             : num [1:19622] -288 -290 -289 -289 -289 -289 -289 -289 -288 -288 ...
##  $ accel_arm_y             : num [1:19622] 109 110 110 111 111 111 111 111 109 110 ...
##  $ accel_arm_z             : num [1:19622] -123 -125 -126 -123 -123 -122 -125 -124 -122 -124 ...
##  $ magnet_arm_x            : num [1:19622] -368 -369 -368 -372 -374 -369 -373 -372 -369 -376 ...
##  $ magnet_arm_y            : num [1:19622] 337 337 344 344 337 342 336 338 341 334 ...
##  $ magnet_arm_z            : num [1:19622] 516 513 513 512 506 513 509 510 518 516 ...
##  $ kurtosis_roll_arm       : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ kurtosis_picth_arm      : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ kurtosis_yaw_arm        : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ skewness_roll_arm       : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ skewness_pitch_arm      : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ skewness_yaw_arm        : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ max_roll_arm            : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ max_picth_arm           : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ max_yaw_arm             : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ min_roll_arm            : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ min_pitch_arm           : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ min_yaw_arm             : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ amplitude_roll_arm      : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ amplitude_pitch_arm     : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ amplitude_yaw_arm       : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ roll_dumbbell           : num [1:19622] 13.1 13.1 12.9 13.4 13.4 ...
##  $ pitch_dumbbell          : num [1:19622] -70.5 -70.6 -70.3 -70.4 -70.4 ...
##  $ yaw_dumbbell            : num [1:19622] -84.9 -84.7 -85.1 -84.9 -84.9 ...
##  $ kurtosis_roll_dumbbell  : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ kurtosis_picth_dumbbell : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ kurtosis_yaw_dumbbell   : logi [1:19622] NA NA NA NA NA NA ...
##  $ skewness_roll_dumbbell  : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ skewness_pitch_dumbbell : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ skewness_yaw_dumbbell   : logi [1:19622] NA NA NA NA NA NA ...
##  $ max_roll_dumbbell       : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ max_picth_dumbbell      : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ max_yaw_dumbbell        : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ min_roll_dumbbell       : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ min_pitch_dumbbell      : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ min_yaw_dumbbell        : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ amplitude_roll_dumbbell : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ amplitude_pitch_dumbbell: num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ amplitude_yaw_dumbbell  : num [1:19622] NA NA NA NA NA NA NA NA NA NA ...
##  $ total_accel_dumbbell    : num [1:19622] 37 37 37 37 37 37 37 37 37 37 ...
##   [list output truncated]
##  - attr(*, "spec")=
##   .. cols(
##   ..   user_name = col_character(),
##   ..   raw_timestamp_part_1 = col_double(),
##   ..   raw_timestamp_part_2 = col_double(),
##   ..   cvtd_timestamp = col_character(),
##   ..   roll_belt = col_double(),
##   ..   pitch_belt = col_double(),
##   ..   yaw_belt = col_double(),
##   ..   total_accel_belt = col_double(),
##   ..   kurtosis_roll_belt = col_double(),
##   ..   kurtosis_picth_belt = col_double(),
##   ..   kurtosis_yaw_belt = col_logical(),
##   ..   skewness_roll_belt = col_double(),
##   ..   skewness_roll_belt.1 = col_double(),
##   ..   skewness_yaw_belt = col_logical(),
##   ..   max_roll_belt = col_double(),
##   ..   max_picth_belt = col_double(),
##   ..   max_yaw_belt = col_double(),
##   ..   min_roll_belt = col_double(),
##   ..   min_pitch_belt = col_double(),
##   ..   min_yaw_belt = col_double(),
##   ..   amplitude_roll_belt = col_double(),
##   ..   amplitude_pitch_belt = col_double(),
##   ..   amplitude_yaw_belt = col_double(),
##   ..   var_total_accel_belt = col_double(),
##   ..   avg_roll_belt = col_double(),
##   ..   stddev_roll_belt = col_double(),
##   ..   var_roll_belt = col_double(),
##   ..   avg_pitch_belt = col_double(),
##   ..   stddev_pitch_belt = col_double(),
##   ..   var_pitch_belt = col_double(),
##   ..   avg_yaw_belt = col_double(),
##   ..   stddev_yaw_belt = col_double(),
##   ..   var_yaw_belt = col_double(),
##   ..   gyros_belt_x = col_double(),
##   ..   gyros_belt_y = col_double(),
##   ..   gyros_belt_z = col_double(),
##   ..   accel_belt_x = col_double(),
##   ..   accel_belt_y = col_double(),
##   ..   accel_belt_z = col_double(),
##   ..   magnet_belt_x = col_double(),
##   ..   magnet_belt_y = col_double(),
##   ..   magnet_belt_z = col_double(),
##   ..   roll_arm = col_double(),
##   ..   pitch_arm = col_double(),
##   ..   yaw_arm = col_double(),
##   ..   total_accel_arm = col_double(),
##   ..   var_accel_arm = col_double(),
##   ..   avg_roll_arm = col_double(),
##   ..   stddev_roll_arm = col_double(),
##   ..   var_roll_arm = col_double(),
##   ..   avg_pitch_arm = col_double(),
##   ..   stddev_pitch_arm = col_double(),
##   ..   var_pitch_arm = col_double(),
##   ..   avg_yaw_arm = col_double(),
##   ..   stddev_yaw_arm = col_double(),
##   ..   var_yaw_arm = col_double(),
##   ..   gyros_arm_x = col_double(),
##   ..   gyros_arm_y = col_double(),
##   ..   gyros_arm_z = col_double(),
##   ..   accel_arm_x = col_double(),
##   ..   accel_arm_y = col_double(),
##   ..   accel_arm_z = col_double(),
##   ..   magnet_arm_x = col_double(),
##   ..   magnet_arm_y = col_double(),
##   ..   magnet_arm_z = col_double(),
##   ..   kurtosis_roll_arm = col_double(),
##   ..   kurtosis_picth_arm = col_double(),
##   ..   kurtosis_yaw_arm = col_double(),
##   ..   skewness_roll_arm = col_double(),
##   ..   skewness_pitch_arm = col_double(),
##   ..   skewness_yaw_arm = col_double(),
##   ..   max_roll_arm = col_double(),
##   ..   max_picth_arm = col_double(),
##   ..   max_yaw_arm = col_double(),
##   ..   min_roll_arm = col_double(),
##   ..   min_pitch_arm = col_double(),
##   ..   min_yaw_arm = col_double(),
##   ..   amplitude_roll_arm = col_double(),
##   ..   amplitude_pitch_arm = col_double(),
##   ..   amplitude_yaw_arm = col_double(),
##   ..   roll_dumbbell = col_double(),
##   ..   pitch_dumbbell = col_double(),
##   ..   yaw_dumbbell = col_double(),
##   ..   kurtosis_roll_dumbbell = col_double(),
##   ..   kurtosis_picth_dumbbell = col_double(),
##   ..   kurtosis_yaw_dumbbell = col_logical(),
##   ..   skewness_roll_dumbbell = col_double(),
##   ..   skewness_pitch_dumbbell = col_double(),
##   ..   skewness_yaw_dumbbell = col_logical(),
##   ..   max_roll_dumbbell = col_double(),
##   ..   max_picth_dumbbell = col_double(),
##   ..   max_yaw_dumbbell = col_double(),
##   ..   min_roll_dumbbell = col_double(),
##   ..   min_pitch_dumbbell = col_double(),
##   ..   min_yaw_dumbbell = col_double(),
##   ..   amplitude_roll_dumbbell = col_double(),
##   ..   amplitude_pitch_dumbbell = col_double(),
##   ..   amplitude_yaw_dumbbell = col_double(),
##   ..   total_accel_dumbbell = col_double(),
##   ..   var_accel_dumbbell = col_double(),
##   ..   avg_roll_dumbbell = col_double(),
##   ..   stddev_roll_dumbbell = col_double(),
##   ..   var_roll_dumbbell = col_double(),
##   ..   avg_pitch_dumbbell = col_double(),
##   ..   stddev_pitch_dumbbell = col_double(),
##   ..   var_pitch_dumbbell = col_double(),
##   ..   avg_yaw_dumbbell = col_double(),
##   ..   stddev_yaw_dumbbell = col_double(),
##   ..   var_yaw_dumbbell = col_double(),
##   ..   gyros_dumbbell_x = col_double(),
##   ..   gyros_dumbbell_y = col_double(),
##   ..   gyros_dumbbell_z = col_double(),
##   ..   accel_dumbbell_x = col_double(),
##   ..   accel_dumbbell_y = col_double(),
##   ..   accel_dumbbell_z = col_double(),
##   ..   magnet_dumbbell_x = col_double(),
##   ..   magnet_dumbbell_y = col_double(),
##   ..   magnet_dumbbell_z = col_double(),
##   ..   roll_forearm = col_double(),
##   ..   pitch_forearm = col_double(),
##   ..   yaw_forearm = col_double(),
##   ..   kurtosis_roll_forearm = col_double(),
##   ..   kurtosis_picth_forearm = col_double(),
##   ..   kurtosis_yaw_forearm = col_logical(),
##   ..   skewness_roll_forearm = col_double(),
##   ..   skewness_pitch_forearm = col_double(),
##   ..   skewness_yaw_forearm = col_logical(),
##   ..   max_roll_forearm = col_double(),
##   ..   max_picth_forearm = col_double(),
##   ..   max_yaw_forearm = col_double(),
##   ..   min_roll_forearm = col_double(),
##   ..   min_pitch_forearm = col_double(),
##   ..   min_yaw_forearm = col_double(),
##   ..   amplitude_roll_forearm = col_double(),
##   ..   amplitude_pitch_forearm = col_double(),
##   ..   amplitude_yaw_forearm = col_double(),
##   ..   total_accel_forearm = col_double(),
##   ..   var_accel_forearm = col_double(),
##   ..   avg_roll_forearm = col_double(),
##   ..   stddev_roll_forearm = col_double(),
##   ..   var_roll_forearm = col_double(),
##   ..   avg_pitch_forearm = col_double(),
##   ..   stddev_pitch_forearm = col_double(),
##   ..   var_pitch_forearm = col_double(),
##   ..   avg_yaw_forearm = col_double(),
##   ..   stddev_yaw_forearm = col_double(),
##   ..   var_yaw_forearm = col_double(),
##   ..   gyros_forearm_x = col_double(),
##   ..   gyros_forearm_y = col_double(),
##   ..   gyros_forearm_z = col_double(),
##   ..   accel_forearm_x = col_double(),
##   ..   accel_forearm_y = col_double(),
##   ..   accel_forearm_z = col_double(),
##   ..   magnet_forearm_x = col_double(),
##   ..   magnet_forearm_y = col_double(),
##   ..   magnet_forearm_z = col_double(),
##   ..   classe = col_character()
##   .. )

Valores de la variable target

unique(df$classe)
## [1] "A" "B" "C" "D" "E"

3.1 Estadísticos

Estudiamos los estadísticos básicos

summary(df)
##   user_name         raw_timestamp_part_1 raw_timestamp_part_2
##  Length:19622       Min.   :1.322e+09    Min.   :   294      
##  Class :character   1st Qu.:1.323e+09    1st Qu.:252912      
##  Mode  :character   Median :1.323e+09    Median :496380      
##                     Mean   :1.323e+09    Mean   :500656      
##                     3rd Qu.:1.323e+09    3rd Qu.:751891      
##                     Max.   :1.323e+09    Max.   :998801      
##                                                              
##  cvtd_timestamp       roll_belt        pitch_belt          yaw_belt      
##  Length:19622       Min.   :-28.90   Min.   :-55.8000   Min.   :-180.00  
##  Class :character   1st Qu.:  1.10   1st Qu.:  1.7600   1st Qu.: -88.30  
##  Mode  :character   Median :113.00   Median :  5.2800   Median : -13.00  
##                     Mean   : 64.41   Mean   :  0.3053   Mean   : -11.21  
##                     3rd Qu.:123.00   3rd Qu.: 14.9000   3rd Qu.:  12.90  
##                     Max.   :162.00   Max.   : 60.3000   Max.   : 179.00  
##                                                                          
##  total_accel_belt kurtosis_roll_belt kurtosis_picth_belt kurtosis_yaw_belt
##  Min.   : 0.00    Min.   :-2.121     Min.   :-2.190      Mode:logical     
##  1st Qu.: 3.00    1st Qu.:-1.329     1st Qu.:-1.107      NA's:19622       
##  Median :17.00    Median :-0.899     Median :-0.151                       
##  Mean   :11.31    Mean   :-0.220     Mean   : 4.334                       
##  3rd Qu.:18.00    3rd Qu.:-0.219     3rd Qu.: 3.178                       
##  Max.   :29.00    Max.   :33.000     Max.   :58.000                       
##                   NA's   :19226      NA's   :19248                        
##  skewness_roll_belt skewness_roll_belt.1 skewness_yaw_belt max_roll_belt    
##  Min.   :-5.745     Min.   :-7.616       Mode:logical      Min.   :-94.300  
##  1st Qu.:-0.444     1st Qu.:-1.114       NA's:19622        1st Qu.:-88.000  
##  Median : 0.000     Median :-0.068                         Median : -5.100  
##  Mean   :-0.026     Mean   :-0.296                         Mean   : -6.667  
##  3rd Qu.: 0.417     3rd Qu.: 0.661                         3rd Qu.: 18.500  
##  Max.   : 3.595     Max.   : 7.348                         Max.   :180.000  
##  NA's   :19225      NA's   :19248                          NA's   :19216    
##  max_picth_belt   max_yaw_belt   min_roll_belt     min_pitch_belt 
##  Min.   : 3.00   Min.   :-2.10   Min.   :-180.00   Min.   : 0.00  
##  1st Qu.: 5.00   1st Qu.:-1.30   1st Qu.: -88.40   1st Qu.: 3.00  
##  Median :18.00   Median :-0.90   Median :  -7.85   Median :16.00  
##  Mean   :12.92   Mean   :-0.22   Mean   : -10.44   Mean   :10.76  
##  3rd Qu.:19.00   3rd Qu.:-0.20   3rd Qu.:   9.05   3rd Qu.:17.00  
##  Max.   :30.00   Max.   :33.00   Max.   : 173.00   Max.   :23.00  
##  NA's   :19216   NA's   :19226   NA's   :19216     NA's   :19216  
##   min_yaw_belt   amplitude_roll_belt amplitude_pitch_belt amplitude_yaw_belt
##  Min.   :-2.10   Min.   :  0.000     Min.   : 0.000       Min.   :0         
##  1st Qu.:-1.30   1st Qu.:  0.300     1st Qu.: 1.000       1st Qu.:0         
##  Median :-0.90   Median :  1.000     Median : 1.000       Median :0         
##  Mean   :-0.22   Mean   :  3.769     Mean   : 2.167       Mean   :0         
##  3rd Qu.:-0.20   3rd Qu.:  2.083     3rd Qu.: 2.000       3rd Qu.:0         
##  Max.   :33.00   Max.   :360.000     Max.   :12.000       Max.   :0         
##  NA's   :19226   NA's   :19216       NA's   :19216        NA's   :19226     
##  var_total_accel_belt avg_roll_belt    stddev_roll_belt var_roll_belt    
##  Min.   : 0.000       Min.   :-27.40   Min.   : 0.000   Min.   :  0.000  
##  1st Qu.: 0.100       1st Qu.:  1.10   1st Qu.: 0.200   1st Qu.:  0.000  
##  Median : 0.200       Median :116.35   Median : 0.400   Median :  0.100  
##  Mean   : 0.926       Mean   : 68.06   Mean   : 1.337   Mean   :  7.699  
##  3rd Qu.: 0.300       3rd Qu.:123.38   3rd Qu.: 0.700   3rd Qu.:  0.500  
##  Max.   :16.500       Max.   :157.40   Max.   :14.200   Max.   :200.700  
##  NA's   :19216        NA's   :19216    NA's   :19216    NA's   :19216    
##  avg_pitch_belt    stddev_pitch_belt var_pitch_belt    avg_yaw_belt     
##  Min.   :-51.400   Min.   :0.000     Min.   : 0.000   Min.   :-138.300  
##  1st Qu.:  2.025   1st Qu.:0.200     1st Qu.: 0.000   1st Qu.: -88.175  
##  Median :  5.200   Median :0.400     Median : 0.100   Median :  -6.550  
##  Mean   :  0.520   Mean   :0.603     Mean   : 0.766   Mean   :  -8.831  
##  3rd Qu.: 15.775   3rd Qu.:0.700     3rd Qu.: 0.500   3rd Qu.:  14.125  
##  Max.   : 59.700   Max.   :4.000     Max.   :16.200   Max.   : 173.500  
##  NA's   :19216     NA's   :19216     NA's   :19216    NA's   :19216     
##  stddev_yaw_belt    var_yaw_belt        gyros_belt_x        gyros_belt_y     
##  Min.   :  0.000   Min.   :    0.000   Min.   :-1.040000   Min.   :-0.64000  
##  1st Qu.:  0.100   1st Qu.:    0.010   1st Qu.:-0.030000   1st Qu.: 0.00000  
##  Median :  0.300   Median :    0.090   Median : 0.030000   Median : 0.02000  
##  Mean   :  1.341   Mean   :  107.487   Mean   :-0.005592   Mean   : 0.03959  
##  3rd Qu.:  0.700   3rd Qu.:    0.475   3rd Qu.: 0.110000   3rd Qu.: 0.11000  
##  Max.   :176.600   Max.   :31183.240   Max.   : 2.220000   Max.   : 0.64000  
##  NA's   :19216     NA's   :19216                                             
##   gyros_belt_z      accel_belt_x       accel_belt_y     accel_belt_z    
##  Min.   :-1.4600   Min.   :-120.000   Min.   :-69.00   Min.   :-275.00  
##  1st Qu.:-0.2000   1st Qu.: -21.000   1st Qu.:  3.00   1st Qu.:-162.00  
##  Median :-0.1000   Median : -15.000   Median : 35.00   Median :-152.00  
##  Mean   :-0.1305   Mean   :  -5.595   Mean   : 30.15   Mean   : -72.59  
##  3rd Qu.:-0.0200   3rd Qu.:  -5.000   3rd Qu.: 61.00   3rd Qu.:  27.00  
##  Max.   : 1.6200   Max.   :  85.000   Max.   :164.00   Max.   : 105.00  
##                                                                         
##  magnet_belt_x   magnet_belt_y   magnet_belt_z       roll_arm      
##  Min.   :-52.0   Min.   :354.0   Min.   :-623.0   Min.   :-180.00  
##  1st Qu.:  9.0   1st Qu.:581.0   1st Qu.:-375.0   1st Qu.: -31.77  
##  Median : 35.0   Median :601.0   Median :-320.0   Median :   0.00  
##  Mean   : 55.6   Mean   :593.7   Mean   :-345.5   Mean   :  17.83  
##  3rd Qu.: 59.0   3rd Qu.:610.0   3rd Qu.:-306.0   3rd Qu.:  77.30  
##  Max.   :485.0   Max.   :673.0   Max.   : 293.0   Max.   : 180.00  
##                                                                    
##    pitch_arm          yaw_arm          total_accel_arm var_accel_arm   
##  Min.   :-88.800   Min.   :-180.0000   Min.   : 1.00   Min.   :  0.00  
##  1st Qu.:-25.900   1st Qu.: -43.1000   1st Qu.:17.00   1st Qu.:  9.03  
##  Median :  0.000   Median :   0.0000   Median :27.00   Median : 40.61  
##  Mean   : -4.612   Mean   :  -0.6188   Mean   :25.51   Mean   : 53.23  
##  3rd Qu.: 11.200   3rd Qu.:  45.8750   3rd Qu.:33.00   3rd Qu.: 75.62  
##  Max.   : 88.500   Max.   : 180.0000   Max.   :66.00   Max.   :331.70  
##                                                        NA's   :19216   
##   avg_roll_arm     stddev_roll_arm    var_roll_arm       avg_pitch_arm    
##  Min.   :-166.67   Min.   :  0.000   Min.   :    0.000   Min.   :-81.773  
##  1st Qu.: -38.37   1st Qu.:  1.376   1st Qu.:    1.898   1st Qu.:-22.770  
##  Median :   0.00   Median :  5.702   Median :   32.517   Median :  0.000  
##  Mean   :  12.68   Mean   : 11.201   Mean   :  417.264   Mean   : -4.901  
##  3rd Qu.:  76.33   3rd Qu.: 14.921   3rd Qu.:  222.647   3rd Qu.:  8.277  
##  Max.   : 163.33   Max.   :161.964   Max.   :26232.208   Max.   : 75.659  
##  NA's   :19216     NA's   :19216     NA's   :19216       NA's   :19216    
##  stddev_pitch_arm var_pitch_arm       avg_yaw_arm       stddev_yaw_arm   
##  Min.   : 0.000   Min.   :   0.000   Min.   :-173.440   Min.   :  0.000  
##  1st Qu.: 1.642   1st Qu.:   2.697   1st Qu.: -29.198   1st Qu.:  2.577  
##  Median : 8.133   Median :  66.146   Median :   0.000   Median : 16.682  
##  Mean   :10.383   Mean   : 195.864   Mean   :   2.359   Mean   : 22.270  
##  3rd Qu.:16.327   3rd Qu.: 266.576   3rd Qu.:  38.185   3rd Qu.: 35.984  
##  Max.   :43.412   Max.   :1884.565   Max.   : 152.000   Max.   :177.044  
##  NA's   :19216    NA's   :19216      NA's   :19216      NA's   :19216    
##   var_yaw_arm         gyros_arm_x        gyros_arm_y       gyros_arm_z     
##  Min.   :    0.000   Min.   :-6.37000   Min.   :-3.4400   Min.   :-2.3300  
##  1st Qu.:    6.642   1st Qu.:-1.33000   1st Qu.:-0.8000   1st Qu.:-0.0700  
##  Median :  278.309   Median : 0.08000   Median :-0.2400   Median : 0.2300  
##  Mean   : 1055.933   Mean   : 0.04277   Mean   :-0.2571   Mean   : 0.2695  
##  3rd Qu.: 1294.850   3rd Qu.: 1.57000   3rd Qu.: 0.1400   3rd Qu.: 0.7200  
##  Max.   :31344.568   Max.   : 4.87000   Max.   : 2.8400   Max.   : 3.0200  
##  NA's   :19216                                                             
##   accel_arm_x       accel_arm_y      accel_arm_z       magnet_arm_x   
##  Min.   :-404.00   Min.   :-318.0   Min.   :-636.00   Min.   :-584.0  
##  1st Qu.:-242.00   1st Qu.: -54.0   1st Qu.:-143.00   1st Qu.:-300.0  
##  Median : -44.00   Median :  14.0   Median : -47.00   Median : 289.0  
##  Mean   : -60.24   Mean   :  32.6   Mean   : -71.25   Mean   : 191.7  
##  3rd Qu.:  84.00   3rd Qu.: 139.0   3rd Qu.:  23.00   3rd Qu.: 637.0  
##  Max.   : 437.00   Max.   : 308.0   Max.   : 292.00   Max.   : 782.0  
##                                                                       
##   magnet_arm_y     magnet_arm_z    kurtosis_roll_arm kurtosis_picth_arm
##  Min.   :-392.0   Min.   :-597.0   Min.   :-1.809    Min.   :-2.084    
##  1st Qu.:  -9.0   1st Qu.: 131.2   1st Qu.:-1.345    1st Qu.:-1.280    
##  Median : 202.0   Median : 444.0   Median :-0.894    Median :-1.010    
##  Mean   : 156.6   Mean   : 306.5   Mean   :-0.366    Mean   :-0.542    
##  3rd Qu.: 323.0   3rd Qu.: 545.0   3rd Qu.:-0.038    3rd Qu.:-0.379    
##  Max.   : 583.0   Max.   : 694.0   Max.   :21.456    Max.   :19.751    
##                                    NA's   :19294     NA's   :19296     
##  kurtosis_yaw_arm skewness_roll_arm skewness_pitch_arm skewness_yaw_arm
##  Min.   :-2.103   Min.   :-2.541    Min.   :-4.565     Min.   :-6.708  
##  1st Qu.:-1.220   1st Qu.:-0.561    1st Qu.:-0.618     1st Qu.:-0.743  
##  Median :-0.733   Median : 0.040    Median :-0.035     Median :-0.133  
##  Mean   : 0.406   Mean   : 0.068    Mean   :-0.065     Mean   :-0.229  
##  3rd Qu.: 0.115   3rd Qu.: 0.671    3rd Qu.: 0.454     3rd Qu.: 0.344  
##  Max.   :56.000   Max.   : 4.394    Max.   : 3.043     Max.   : 7.483  
##  NA's   :19227    NA's   :19293     NA's   :19296      NA's   :19227   
##   max_roll_arm     max_picth_arm       max_yaw_arm     min_roll_arm   
##  Min.   :-73.100   Min.   :-173.000   Min.   : 4.00   Min.   :-89.10  
##  1st Qu.: -0.175   1st Qu.:  -1.975   1st Qu.:29.00   1st Qu.:-41.98  
##  Median :  4.950   Median :  23.250   Median :34.00   Median :-22.45  
##  Mean   : 11.236   Mean   :  35.751   Mean   :35.46   Mean   :-21.22  
##  3rd Qu.: 26.775   3rd Qu.:  95.975   3rd Qu.:41.00   3rd Qu.:  0.00  
##  Max.   : 85.500   Max.   : 180.000   Max.   :65.00   Max.   : 66.40  
##  NA's   :19216     NA's   :19216      NA's   :19216   NA's   :19216   
##  min_pitch_arm      min_yaw_arm    amplitude_roll_arm amplitude_pitch_arm
##  Min.   :-180.00   Min.   : 1.00   Min.   :  0.000    Min.   :  0.000    
##  1st Qu.: -72.62   1st Qu.: 8.00   1st Qu.:  5.425    1st Qu.:  9.925    
##  Median : -33.85   Median :13.00   Median : 28.450    Median : 54.900    
##  Mean   : -33.92   Mean   :14.66   Mean   : 32.452    Mean   : 69.677    
##  3rd Qu.:   0.00   3rd Qu.:19.00   3rd Qu.: 50.960    3rd Qu.:115.175    
##  Max.   : 152.00   Max.   :38.00   Max.   :119.500    Max.   :360.000    
##  NA's   :19216     NA's   :19216   NA's   :19216      NA's   :19216      
##  amplitude_yaw_arm roll_dumbbell     pitch_dumbbell     yaw_dumbbell     
##  Min.   : 0.00     Min.   :-153.71   Min.   :-149.59   Min.   :-150.871  
##  1st Qu.:13.00     1st Qu.: -18.49   1st Qu.: -40.89   1st Qu.: -77.644  
##  Median :22.00     Median :  48.17   Median : -20.96   Median :  -3.324  
##  Mean   :20.79     Mean   :  23.84   Mean   : -10.78   Mean   :   1.674  
##  3rd Qu.:28.75     3rd Qu.:  67.61   3rd Qu.:  17.50   3rd Qu.:  79.643  
##  Max.   :52.00     Max.   : 153.55   Max.   : 149.40   Max.   : 154.952  
##  NA's   :19216                                                           
##  kurtosis_roll_dumbbell kurtosis_picth_dumbbell kurtosis_yaw_dumbbell
##  Min.   :-2.174         Min.   :-2.200          Mode:logical         
##  1st Qu.:-0.682         1st Qu.:-0.721          NA's:19622           
##  Median :-0.033         Median :-0.133                               
##  Mean   : 0.452         Mean   : 0.286                               
##  3rd Qu.: 0.940         3rd Qu.: 0.584                               
##  Max.   :54.998         Max.   :55.628                               
##  NA's   :19221          NA's   :19218                                
##  skewness_roll_dumbbell skewness_pitch_dumbbell skewness_yaw_dumbbell
##  Min.   :-7.384         Min.   :-7.447          Mode:logical         
##  1st Qu.:-0.581         1st Qu.:-0.526          NA's:19622           
##  Median :-0.076         Median :-0.091                               
##  Mean   :-0.115         Mean   :-0.035                               
##  3rd Qu.: 0.400         3rd Qu.: 0.505                               
##  Max.   : 1.958         Max.   : 3.769                               
##  NA's   :19220          NA's   :19217                                
##  max_roll_dumbbell max_picth_dumbbell max_yaw_dumbbell min_roll_dumbbell
##  Min.   :-70.10    Min.   :-112.90    Min.   :-2.20    Min.   :-149.60  
##  1st Qu.:-27.15    1st Qu.: -66.70    1st Qu.:-0.70    1st Qu.: -59.67  
##  Median : 14.85    Median :  40.05    Median : 0.00    Median : -43.55  
##  Mean   : 13.76    Mean   :  32.75    Mean   : 0.45    Mean   : -41.24  
##  3rd Qu.: 50.58    3rd Qu.: 133.22    3rd Qu.: 0.90    3rd Qu.: -25.20  
##  Max.   :137.00    Max.   : 155.00    Max.   :55.00    Max.   :  73.20  
##  NA's   :19216     NA's   :19216      NA's   :19221    NA's   :19216    
##  min_pitch_dumbbell min_yaw_dumbbell amplitude_roll_dumbbell
##  Min.   :-147.00    Min.   :-2.20    Min.   :  0.00         
##  1st Qu.: -91.80    1st Qu.:-0.70    1st Qu.: 14.97         
##  Median : -66.15    Median : 0.00    Median : 35.05         
##  Mean   : -33.18    Mean   : 0.45    Mean   : 55.00         
##  3rd Qu.:  21.20    3rd Qu.: 0.90    3rd Qu.: 81.04         
##  Max.   : 120.90    Max.   :55.00    Max.   :256.48         
##  NA's   :19216      NA's   :19221    NA's   :19216          
##  amplitude_pitch_dumbbell amplitude_yaw_dumbbell total_accel_dumbbell
##  Min.   :  0.00           Min.   :0              Min.   : 0.00       
##  1st Qu.: 17.06           1st Qu.:0              1st Qu.: 4.00       
##  Median : 41.73           Median :0              Median :10.00       
##  Mean   : 65.93           Mean   :0              Mean   :13.72       
##  3rd Qu.: 99.55           3rd Qu.:0              3rd Qu.:19.00       
##  Max.   :273.59           Max.   :0              Max.   :58.00       
##  NA's   :19216            NA's   :19221                              
##  var_accel_dumbbell avg_roll_dumbbell stddev_roll_dumbbell var_roll_dumbbell 
##  Min.   :  0.000    Min.   :-128.96   Min.   :  0.000      Min.   :    0.00  
##  1st Qu.:  0.378    1st Qu.: -12.33   1st Qu.:  4.639      1st Qu.:   21.52  
##  Median :  1.000    Median :  48.23   Median : 12.204      Median :  148.95  
##  Mean   :  4.388    Mean   :  23.86   Mean   : 20.761      Mean   : 1020.27  
##  3rd Qu.:  3.434    3rd Qu.:  64.37   3rd Qu.: 26.356      3rd Qu.:  694.65  
##  Max.   :230.428    Max.   : 125.99   Max.   :123.778      Max.   :15321.01  
##  NA's   :19216      NA's   :19216     NA's   :19216        NA's   :19216     
##  avg_pitch_dumbbell stddev_pitch_dumbbell var_pitch_dumbbell avg_yaw_dumbbell  
##  Min.   :-70.73     Min.   : 0.000        Min.   :   0.00    Min.   :-117.950  
##  1st Qu.:-42.00     1st Qu.: 3.482        1st Qu.:  12.12    1st Qu.: -76.696  
##  Median :-19.91     Median : 8.089        Median :  65.44    Median :  -4.505  
##  Mean   :-12.33     Mean   :13.147        Mean   : 350.31    Mean   :   0.202  
##  3rd Qu.: 13.21     3rd Qu.:19.238        3rd Qu.: 370.11    3rd Qu.:  71.234  
##  Max.   : 94.28     Max.   :82.680        Max.   :6836.02    Max.   : 134.905  
##  NA's   :19216      NA's   :19216         NA's   :19216      NA's   :19216     
##  stddev_yaw_dumbbell var_yaw_dumbbell   gyros_dumbbell_x    gyros_dumbbell_y  
##  Min.   :  0.000     Min.   :    0.00   Min.   :-204.0000   Min.   :-2.10000  
##  1st Qu.:  3.885     1st Qu.:   15.09   1st Qu.:  -0.0300   1st Qu.:-0.14000  
##  Median : 10.264     Median :  105.35   Median :   0.1300   Median : 0.03000  
##  Mean   : 16.647     Mean   :  589.84   Mean   :   0.1611   Mean   : 0.04606  
##  3rd Qu.: 24.674     3rd Qu.:  608.79   3rd Qu.:   0.3500   3rd Qu.: 0.21000  
##  Max.   :107.088     Max.   :11467.91   Max.   :   2.2200   Max.   :52.00000  
##  NA's   :19216       NA's   :19216                                            
##  gyros_dumbbell_z  accel_dumbbell_x  accel_dumbbell_y  accel_dumbbell_z 
##  Min.   : -2.380   Min.   :-419.00   Min.   :-189.00   Min.   :-334.00  
##  1st Qu.: -0.310   1st Qu.: -50.00   1st Qu.:  -8.00   1st Qu.:-142.00  
##  Median : -0.130   Median :  -8.00   Median :  41.50   Median :  -1.00  
##  Mean   : -0.129   Mean   : -28.62   Mean   :  52.63   Mean   : -38.32  
##  3rd Qu.:  0.030   3rd Qu.:  11.00   3rd Qu.: 111.00   3rd Qu.:  38.00  
##  Max.   :317.000   Max.   : 235.00   Max.   : 315.00   Max.   : 318.00  
##                                                                         
##  magnet_dumbbell_x magnet_dumbbell_y magnet_dumbbell_z  roll_forearm      
##  Min.   :-643.0    Min.   :-3600     Min.   :-262.00   Min.   :-180.0000  
##  1st Qu.:-535.0    1st Qu.:  231     1st Qu.: -45.00   1st Qu.:  -0.7375  
##  Median :-479.0    Median :  311     Median :  13.00   Median :  21.7000  
##  Mean   :-328.5    Mean   :  221     Mean   :  46.05   Mean   :  33.8265  
##  3rd Qu.:-304.0    3rd Qu.:  390     3rd Qu.:  95.00   3rd Qu.: 140.0000  
##  Max.   : 592.0    Max.   :  633     Max.   : 452.00   Max.   : 180.0000  
##                                                                           
##  pitch_forearm     yaw_forearm      kurtosis_roll_forearm
##  Min.   :-72.50   Min.   :-180.00   Min.   :-1.879       
##  1st Qu.:  0.00   1st Qu.: -68.60   1st Qu.:-1.398       
##  Median :  9.24   Median :   0.00   Median :-1.119       
##  Mean   : 10.71   Mean   :  19.21   Mean   :-0.689       
##  3rd Qu.: 28.40   3rd Qu.: 110.00   3rd Qu.:-0.618       
##  Max.   : 89.80   Max.   : 180.00   Max.   :40.060       
##                                     NA's   :19300        
##  kurtosis_picth_forearm kurtosis_yaw_forearm skewness_roll_forearm
##  Min.   :-2.098         Mode:logical         Min.   :-2.297       
##  1st Qu.:-1.376         NA's:19622           1st Qu.:-0.402       
##  Median :-0.890                              Median : 0.003       
##  Mean   : 0.419                              Mean   :-0.009       
##  3rd Qu.: 0.054                              3rd Qu.: 0.370       
##  Max.   :33.626                              Max.   : 5.856       
##  NA's   :19301                               NA's   :19299        
##  skewness_pitch_forearm skewness_yaw_forearm max_roll_forearm max_picth_forearm
##  Min.   :-5.241         Mode:logical         Min.   :-66.60   Min.   :-151.00  
##  1st Qu.:-0.881         NA's:19622           1st Qu.:  0.00   1st Qu.:   0.00  
##  Median :-0.156                              Median : 26.80   Median : 113.00  
##  Mean   :-0.223                              Mean   : 24.49   Mean   :  81.49  
##  3rd Qu.: 0.514                              3rd Qu.: 45.95   3rd Qu.: 174.75  
##  Max.   : 4.464                              Max.   : 89.80   Max.   : 180.00  
##  NA's   :19301                               NA's   :19216    NA's   :19216    
##  max_yaw_forearm  min_roll_forearm  min_pitch_forearm min_yaw_forearm 
##  Min.   :-1.900   Min.   :-72.500   Min.   :-180.00   Min.   :-1.900  
##  1st Qu.:-1.400   1st Qu.: -6.075   1st Qu.:-175.00   1st Qu.:-1.400  
##  Median :-1.100   Median :  0.000   Median : -61.00   Median :-1.100  
##  Mean   :-0.689   Mean   : -0.167   Mean   : -57.57   Mean   :-0.689  
##  3rd Qu.:-0.600   3rd Qu.: 12.075   3rd Qu.:   0.00   3rd Qu.:-0.600  
##  Max.   :40.100   Max.   : 62.100   Max.   : 167.00   Max.   :40.100  
##  NA's   :19300    NA's   :19216     NA's   :19216     NA's   :19300   
##  amplitude_roll_forearm amplitude_pitch_forearm amplitude_yaw_forearm
##  Min.   :  0.000        Min.   :  0.0           Min.   :0            
##  1st Qu.:  1.125        1st Qu.:  2.0           1st Qu.:0            
##  Median : 17.770        Median : 83.7           Median :0            
##  Mean   : 24.653        Mean   :139.1           Mean   :0            
##  3rd Qu.: 39.875        3rd Qu.:350.0           3rd Qu.:0            
##  Max.   :126.000        Max.   :360.0           Max.   :0            
##  NA's   :19216          NA's   :19216           NA's   :19300        
##  total_accel_forearm var_accel_forearm avg_roll_forearm   stddev_roll_forearm
##  Min.   :  0.00      Min.   :  0.000   Min.   :-177.234   Min.   :  0.000    
##  1st Qu.: 29.00      1st Qu.:  6.759   1st Qu.:  -0.909   1st Qu.:  0.428    
##  Median : 36.00      Median : 21.165   Median :  11.172   Median :  8.030    
##  Mean   : 34.72      Mean   : 33.502   Mean   :  33.165   Mean   : 41.986    
##  3rd Qu.: 41.00      3rd Qu.: 51.240   3rd Qu.: 107.132   3rd Qu.: 85.373    
##  Max.   :108.00      Max.   :172.606   Max.   : 177.256   Max.   :179.171    
##                      NA's   :19216     NA's   :19216      NA's   :19216      
##  var_roll_forearm   avg_pitch_forearm stddev_pitch_forearm var_pitch_forearm 
##  Min.   :    0.00   Min.   :-68.17    Min.   : 0.000       Min.   :   0.000  
##  1st Qu.:    0.18   1st Qu.:  0.00    1st Qu.: 0.336       1st Qu.:   0.113  
##  Median :   64.48   Median : 12.02    Median : 5.516       Median :  30.425  
##  Mean   : 5274.10   Mean   : 11.79    Mean   : 7.977       Mean   : 139.593  
##  3rd Qu.: 7289.08   3rd Qu.: 28.48    3rd Qu.:12.866       3rd Qu.: 165.532  
##  Max.   :32102.24   Max.   : 72.09    Max.   :47.745       Max.   :2279.617  
##  NA's   :19216      NA's   :19216     NA's   :19216        NA's   :19216     
##  avg_yaw_forearm   stddev_yaw_forearm var_yaw_forearm    gyros_forearm_x  
##  Min.   :-155.06   Min.   :  0.000    Min.   :    0.00   Min.   :-22.000  
##  1st Qu.: -26.26   1st Qu.:  0.524    1st Qu.:    0.27   1st Qu.: -0.220  
##  Median :   0.00   Median : 24.743    Median :  612.21   Median :  0.050  
##  Mean   :  18.00   Mean   : 44.854    Mean   : 4639.85   Mean   :  0.158  
##  3rd Qu.:  85.79   3rd Qu.: 85.817    3rd Qu.: 7368.41   3rd Qu.:  0.560  
##  Max.   : 169.24   Max.   :197.508    Max.   :39009.33   Max.   :  3.970  
##  NA's   :19216     NA's   :19216      NA's   :19216                       
##  gyros_forearm_y     gyros_forearm_z    accel_forearm_x   accel_forearm_y 
##  Min.   : -7.02000   Min.   : -8.0900   Min.   :-498.00   Min.   :-632.0  
##  1st Qu.: -1.46000   1st Qu.: -0.1800   1st Qu.:-178.00   1st Qu.:  57.0  
##  Median :  0.03000   Median :  0.0800   Median : -57.00   Median : 201.0  
##  Mean   :  0.07517   Mean   :  0.1512   Mean   : -61.65   Mean   : 163.7  
##  3rd Qu.:  1.62000   3rd Qu.:  0.4900   3rd Qu.:  76.00   3rd Qu.: 312.0  
##  Max.   :311.00000   Max.   :231.0000   Max.   : 477.00   Max.   : 923.0  
##                                                                           
##  accel_forearm_z   magnet_forearm_x  magnet_forearm_y magnet_forearm_z
##  Min.   :-446.00   Min.   :-1280.0   Min.   :-896.0   Min.   :-973.0  
##  1st Qu.:-182.00   1st Qu.: -616.0   1st Qu.:   2.0   1st Qu.: 191.0  
##  Median : -39.00   Median : -378.0   Median : 591.0   Median : 511.0  
##  Mean   : -55.29   Mean   : -312.6   Mean   : 380.1   Mean   : 393.6  
##  3rd Qu.:  26.00   3rd Qu.:  -73.0   3rd Qu.: 737.0   3rd Qu.: 653.0  
##  Max.   : 291.00   Max.   :  672.0   Max.   :1480.0   Max.   :1090.0  
##                                                                       
##     classe         
##  Length:19622      
##  Class :character  
##  Mode  :character  
##                    
##                    
##                    
## 

3.1.1 Variables numéricas

Observamos algunos problemas:

  • Las variables tienen magnitudes muy dispares. Adicionalmente, algunas toman valores negativos.
  • Existen variables con muchos valores nulos

Trataremos estos problemas más adelante

3.1.2 Variables categóricas

Observamos algunos problemas:

  • La variable user_name identifica el nombre del usuario. Debe ser descartada, no tiene valor predictivo.
df$user_name <- NULL
dim(df)
## [1] 19622   156

3.2 Valores nulos

Hemos detectado que los datos tienen columnas con demasiados nulos. Vamos a tratar esos casos.

colSums(is.na.data.frame(df))
##     raw_timestamp_part_1     raw_timestamp_part_2           cvtd_timestamp 
##                        0                        0                        0 
##                roll_belt               pitch_belt                 yaw_belt 
##                        0                        0                        0 
##         total_accel_belt       kurtosis_roll_belt      kurtosis_picth_belt 
##                        0                    19226                    19248 
##        kurtosis_yaw_belt       skewness_roll_belt     skewness_roll_belt.1 
##                    19622                    19225                    19248 
##        skewness_yaw_belt            max_roll_belt           max_picth_belt 
##                    19622                    19216                    19216 
##             max_yaw_belt            min_roll_belt           min_pitch_belt 
##                    19226                    19216                    19216 
##             min_yaw_belt      amplitude_roll_belt     amplitude_pitch_belt 
##                    19226                    19216                    19216 
##       amplitude_yaw_belt     var_total_accel_belt            avg_roll_belt 
##                    19226                    19216                    19216 
##         stddev_roll_belt            var_roll_belt           avg_pitch_belt 
##                    19216                    19216                    19216 
##        stddev_pitch_belt           var_pitch_belt             avg_yaw_belt 
##                    19216                    19216                    19216 
##          stddev_yaw_belt             var_yaw_belt             gyros_belt_x 
##                    19216                    19216                        0 
##             gyros_belt_y             gyros_belt_z             accel_belt_x 
##                        0                        0                        0 
##             accel_belt_y             accel_belt_z            magnet_belt_x 
##                        0                        0                        0 
##            magnet_belt_y            magnet_belt_z                 roll_arm 
##                        0                        0                        0 
##                pitch_arm                  yaw_arm          total_accel_arm 
##                        0                        0                        0 
##            var_accel_arm             avg_roll_arm          stddev_roll_arm 
##                    19216                    19216                    19216 
##             var_roll_arm            avg_pitch_arm         stddev_pitch_arm 
##                    19216                    19216                    19216 
##            var_pitch_arm              avg_yaw_arm           stddev_yaw_arm 
##                    19216                    19216                    19216 
##              var_yaw_arm              gyros_arm_x              gyros_arm_y 
##                    19216                        0                        0 
##              gyros_arm_z              accel_arm_x              accel_arm_y 
##                        0                        0                        0 
##              accel_arm_z             magnet_arm_x             magnet_arm_y 
##                        0                        0                        0 
##             magnet_arm_z        kurtosis_roll_arm       kurtosis_picth_arm 
##                        0                    19294                    19296 
##         kurtosis_yaw_arm        skewness_roll_arm       skewness_pitch_arm 
##                    19227                    19293                    19296 
##         skewness_yaw_arm             max_roll_arm            max_picth_arm 
##                    19227                    19216                    19216 
##              max_yaw_arm             min_roll_arm            min_pitch_arm 
##                    19216                    19216                    19216 
##              min_yaw_arm       amplitude_roll_arm      amplitude_pitch_arm 
##                    19216                    19216                    19216 
##        amplitude_yaw_arm            roll_dumbbell           pitch_dumbbell 
##                    19216                        0                        0 
##             yaw_dumbbell   kurtosis_roll_dumbbell  kurtosis_picth_dumbbell 
##                        0                    19221                    19218 
##    kurtosis_yaw_dumbbell   skewness_roll_dumbbell  skewness_pitch_dumbbell 
##                    19622                    19220                    19217 
##    skewness_yaw_dumbbell        max_roll_dumbbell       max_picth_dumbbell 
##                    19622                    19216                    19216 
##         max_yaw_dumbbell        min_roll_dumbbell       min_pitch_dumbbell 
##                    19221                    19216                    19216 
##         min_yaw_dumbbell  amplitude_roll_dumbbell amplitude_pitch_dumbbell 
##                    19221                    19216                    19216 
##   amplitude_yaw_dumbbell     total_accel_dumbbell       var_accel_dumbbell 
##                    19221                        0                    19216 
##        avg_roll_dumbbell     stddev_roll_dumbbell        var_roll_dumbbell 
##                    19216                    19216                    19216 
##       avg_pitch_dumbbell    stddev_pitch_dumbbell       var_pitch_dumbbell 
##                    19216                    19216                    19216 
##         avg_yaw_dumbbell      stddev_yaw_dumbbell         var_yaw_dumbbell 
##                    19216                    19216                    19216 
##         gyros_dumbbell_x         gyros_dumbbell_y         gyros_dumbbell_z 
##                        0                        0                        0 
##         accel_dumbbell_x         accel_dumbbell_y         accel_dumbbell_z 
##                        0                        0                        0 
##        magnet_dumbbell_x        magnet_dumbbell_y        magnet_dumbbell_z 
##                        0                        0                        0 
##             roll_forearm            pitch_forearm              yaw_forearm 
##                        0                        0                        0 
##    kurtosis_roll_forearm   kurtosis_picth_forearm     kurtosis_yaw_forearm 
##                    19300                    19301                    19622 
##    skewness_roll_forearm   skewness_pitch_forearm     skewness_yaw_forearm 
##                    19299                    19301                    19622 
##         max_roll_forearm        max_picth_forearm          max_yaw_forearm 
##                    19216                    19216                    19300 
##         min_roll_forearm        min_pitch_forearm          min_yaw_forearm 
##                    19216                    19216                    19300 
##   amplitude_roll_forearm  amplitude_pitch_forearm    amplitude_yaw_forearm 
##                    19216                    19216                    19300 
##      total_accel_forearm        var_accel_forearm         avg_roll_forearm 
##                        0                    19216                    19216 
##      stddev_roll_forearm         var_roll_forearm        avg_pitch_forearm 
##                    19216                    19216                    19216 
##     stddev_pitch_forearm        var_pitch_forearm          avg_yaw_forearm 
##                    19216                    19216                    19216 
##       stddev_yaw_forearm          var_yaw_forearm          gyros_forearm_x 
##                    19216                    19216                        0 
##          gyros_forearm_y          gyros_forearm_z          accel_forearm_x 
##                        0                        0                        0 
##          accel_forearm_y          accel_forearm_z         magnet_forearm_x 
##                        0                        0                        0 
##         magnet_forearm_y         magnet_forearm_z                   classe 
##                        0                        0                        0

Las 100 columnas identificadas contienen demasiados nulos. Las eliminamos.

cols_var_nulo <- colnames(df)[colSums(is.na(df)) > 0]

df <- df[, !colnames(df) %in% cols_var_nulo]
dim(df)
## [1] 19622    56

3.3 Análisis de coherencia

3.3.1 Variables duplicadas

No existen variables duplicadas

sum(duplicated(t(df)))
## [1] 0

3.3.2 Registros duplicados

No existen registros duplicados

sum(duplicated(df))
## [1] 0

3.3.3 Campos/variables con un único valor

No existen campos que tengan siempre un mismo valor.

sum(
  sapply(df, function(x) length(unique(x)) == 1)
)
## [1] 0

4 Análisis Exploratorio de Datos.

4.1 Visualizaciones

4.1.1 Variables continuas

Analicemos las variables numéricas. Para ello utilizamos histogramas y boxplots.

varNumericas <- names(df[sapply(df, class) == "numeric"])


par(mfrow=c(5,2), mar = c(2,0,2,2))
for (var in varNumericas){
  boxplot(df[[var]], horizontal=TRUE, outline=TRUE, col = "green3", main = var)
  hist(df[[var]], main = var, col = "pink2") 
}
## Warning in breaks[-1L] + breaks[-nB]: NAs producidos por enteros excedidos

En general, observamos distribuciones alejadas de la distribución normal: distribuciones multimodales (sobre todo bimodales y trimodales), distribuciones con largas colas, etc. Además, en algunas variables, observamos la presencia de valores atípicos. Esto puede afectar al rendimiento de algunos modelos, por lo que debemos tenerlo en cuenta.

4.1.2 Variables categóricas

Para las variables categóricas realizamos diagramas de barras.

varCategoricas <- names(df[sapply(df, class) == "character"])

for (var in varCategoricas){
  counts <- table(df[,var])
  density <- counts / sum(counts)
  print(paste("Distribución: ", var))
  print(density)
  barplot(density, main = paste("Gráfico de barras de: ", var), horiz = FALSE, col="lightblue3")
}
## [1] "Distribución:  cvtd_timestamp"
## 
## 02/12/2011 13:32 02/12/2011 13:33 02/12/2011 13:34 02/12/2011 13:35 
##      0.009020487      0.067322393      0.070074406      0.051931505 
## 02/12/2011 14:56 02/12/2011 14:57 02/12/2011 14:58 02/12/2011 14:59 
##      0.011976353      0.070329222      0.069513811      0.028386505 
## 05/12/2011 11:23 05/12/2011 11:24 05/12/2011 11:25 05/12/2011 14:22 
##      0.009683009      0.076291917      0.072622567      0.013607176 
## 05/12/2011 14:23 05/12/2011 14:24 28/11/2011 14:13 28/11/2011 14:14 
##      0.069819590      0.049587198      0.042452349      0.076342880 
## 28/11/2011 14:15 30/11/2011 17:10 30/11/2011 17:11 30/11/2011 17:12 
##      0.037661808      0.044287025      0.073387015      0.055702783

## [1] "Distribución:  classe"
## 
##         A         B         C         D         E 
## 0.2843747 0.1935073 0.1743961 0.1638977 0.1838243

Los datos reflejan cuatro fechas: dos a finales de Noviembre 2011, dos a principios de Diciembre 2011. La fecha exacta no es un buen predictor, por lo que más adelante trataremos este campo.

Las clases están aproximadamente balanceadas, no nos enfrentamos a un problema de clases fuertemente desbalanceadas.

4.2 Matriz de correlaciones

Estudiamos la correlación entre las variables. Para poder incluir la variable dependiente, que es de tipo categórico, le aplicamos una transformación dummy.

class_unique_values <- levels(as.factor(df$classe))

class_dummies <- data.frame(model.matrix(~classe, data = df))[ ,2:length(class_unique_values)]
rm(class_unique_values) # eliminamos el objeto class_unique_values, ya no es necesario

head(class_dummies)
##   classeB classeC classeD classeE
## 1       0       0       0       0
## 2       0       0       0       0
## 3       0       0       0       0
## 4       0       0       0       0
## 5       0       0       0       0
## 6       0       0       0       0

La incluímos en el dataframe, que renombramos como df_dm

df_dm <- df

df_dm$classe <- NULL
df_dm <- bind_cols(df_dm, class_dummies)
rm(class_dummies) # eliminamos el objeto class_dummies, ya no es necesario

tail(df_dm)
## # A tibble: 6 x 59
##   raw_timestamp_p~ raw_timestamp_p~ cvtd_timestamp roll_belt pitch_belt yaw_belt
##              <dbl>            <dbl> <chr>              <dbl>      <dbl>    <dbl>
## 1       1322832937           588324 02/12/2011 13~       148      -34.7      129
## 2       1322832937           588376 02/12/2011 13~       147      -34.8      129
## 3       1322832937           596287 02/12/2011 13~       145      -35.3      130
## 4       1322832937           636283 02/12/2011 13~       145      -35.5      130
## 5       1322832937           964299 02/12/2011 13~       143      -35.9      131
## 6       1322832937           972293 02/12/2011 13~       143      -36        132
## # ... with 53 more variables: total_accel_belt <dbl>, gyros_belt_x <dbl>,
## #   gyros_belt_y <dbl>, gyros_belt_z <dbl>, accel_belt_x <dbl>,
## #   accel_belt_y <dbl>, accel_belt_z <dbl>, magnet_belt_x <dbl>,
## #   magnet_belt_y <dbl>, magnet_belt_z <dbl>, roll_arm <dbl>, pitch_arm <dbl>,
## #   yaw_arm <dbl>, total_accel_arm <dbl>, gyros_arm_x <dbl>, gyros_arm_y <dbl>,
## #   gyros_arm_z <dbl>, accel_arm_x <dbl>, accel_arm_y <dbl>, accel_arm_z <dbl>,
## #   magnet_arm_x <dbl>, magnet_arm_y <dbl>, magnet_arm_z <dbl>,
## #   roll_dumbbell <dbl>, pitch_dumbbell <dbl>, yaw_dumbbell <dbl>,
## #   total_accel_dumbbell <dbl>, gyros_dumbbell_x <dbl>, gyros_dumbbell_y <dbl>,
## #   gyros_dumbbell_z <dbl>, accel_dumbbell_x <dbl>, accel_dumbbell_y <dbl>,
## #   accel_dumbbell_z <dbl>, magnet_dumbbell_x <dbl>, magnet_dumbbell_y <dbl>,
## #   magnet_dumbbell_z <dbl>, roll_forearm <dbl>, pitch_forearm <dbl>,
## #   yaw_forearm <dbl>, total_accel_forearm <dbl>, gyros_forearm_x <dbl>,
## #   gyros_forearm_y <dbl>, gyros_forearm_z <dbl>, accel_forearm_x <dbl>,
## #   accel_forearm_y <dbl>, accel_forearm_z <dbl>, magnet_forearm_x <dbl>,
## #   magnet_forearm_y <dbl>, magnet_forearm_z <dbl>, classeB <dbl>,
## #   classeC <dbl>, classeD <dbl>, classeE <dbl>

representamos la matriz de correlaciones

corrplot(
  cor( df_dm[sapply(df_dm, class) == "numeric"] )
)

Observamos que, en general, las variables independientes están débilmente correladas con la variable dependiente. Por otro lado, algunas variables independientes están fuertemente correladas entre sí.

5 Creación y transformación de variables

5.1 Variables de fecha y tiempo

La variable de fecha hora cvtd_timestamp está codificada en tiempo UNIX en los campos raw_timestamp_part_1 (parte entera del timestamp) y raw_timestamp_part_2 (parte decimal del timestamp).

Además, la fecha precisa no es buen predictor. Una opción sería extaer información útil como la hora, día de la semana, día del mes o mes para detectar patrones relevantes. Sin embargo, en nuestro dataset existen solamente 4 días registrados, y en cada día el intervalo horario es muy reducido.

sort(
  levels(as.factor(df$cvtd_timestamp))
)
##  [1] "02/12/2011 13:32" "02/12/2011 13:33" "02/12/2011 13:34" "02/12/2011 13:35"
##  [5] "02/12/2011 14:56" "02/12/2011 14:57" "02/12/2011 14:58" "02/12/2011 14:59"
##  [9] "05/12/2011 11:23" "05/12/2011 11:24" "05/12/2011 11:25" "05/12/2011 14:22"
## [13] "05/12/2011 14:23" "05/12/2011 14:24" "28/11/2011 14:13" "28/11/2011 14:14"
## [17] "28/11/2011 14:15" "30/11/2011 17:10" "30/11/2011 17:11" "30/11/2011 17:12"

Por lo tanto, optamos por eliminar esta información:

cols_to_delete <- c("cvtd_timestamp", "raw_timestamp_part_1", "raw_timestamp_part_2")

df <- df[, !colnames(df) %in% cols_to_delete]
df_dm <- df_dm[, !colnames(df_dm) %in% cols_to_delete]

# alternativa:
# df <- df %>% select(-cvtd_timestamp,-raw_timestamp_part_1,-raw_timestamp_part_2)

dim(df)
## [1] 19622    53
dim(df_dm)
## [1] 19622    56

6 Exploración de modelos

Eliminamos la etiqueta de datos para trabajar con un problema no supervisado. Normalizamos los datos.

df_norm <- data.Normalization( data.frame(df[, 1:52]), "n4")  # n4 - unitization with zero minimum ((x-min)/range))
head(df_norm)
##   roll_belt pitch_belt  yaw_belt total_accel_belt gyros_belt_x gyros_belt_y
## 1 0.1587742  0.5501292 0.2384401        0.1034483    0.3190184     0.500000
## 2 0.1587742  0.5501292 0.2384401        0.1034483    0.3251534     0.500000
## 3 0.1588266  0.5501292 0.2384401        0.1034483    0.3190184     0.500000
## 4 0.1591409  0.5499569 0.2384401        0.1034483    0.3251534     0.500000
## 5 0.1591409  0.5501292 0.2384401        0.1034483    0.3251534     0.515625
## 6 0.1589838  0.5500431 0.2384401        0.1034483    0.3251534     0.500000
##   gyros_belt_z accel_belt_x accel_belt_y accel_belt_z magnet_belt_x
## 1    0.4675325    0.4829268    0.3133047    0.7815789    0.09124767
## 2    0.4675325    0.4780488    0.3133047    0.7815789    0.08379888
## 3    0.4675325    0.4878049    0.3175966    0.7842105    0.09310987
## 4    0.4642857    0.4780488    0.3090129    0.7789474    0.08566108
## 5    0.4675325    0.4829268    0.3047210    0.7868421    0.08566108
## 6    0.4675325    0.4829268    0.3133047    0.7789474    0.09683426
##   magnet_belt_y magnet_belt_z  roll_arm pitch_arm    yaw_arm total_accel_arm
## 1     0.7680251     0.3384279 0.1444444 0.6277496 0.05277778       0.5076923
## 2     0.7962382     0.3406114 0.1444444 0.6277496 0.05277778       0.5076923
## 3     0.7711599     0.3471616 0.1444444 0.6277496 0.05277778       0.5076923
## 4     0.7836991     0.3417031 0.1444444 0.6254935 0.05277778       0.5076923
## 5     0.7711599     0.3504367 0.1444444 0.6254935 0.05277778       0.5076923
## 6     0.7805643     0.3395197 0.1444444 0.6249295 0.05277778       0.5076923
##   gyros_arm_x gyros_arm_y gyros_arm_z accel_arm_x accel_arm_y accel_arm_z
## 1   0.5667260   0.5477707   0.4317757   0.1379310   0.6821086   0.5528017
## 2   0.5685053   0.5445860   0.4317757   0.1355529   0.6837061   0.5506466
## 3   0.5685053   0.5445860   0.4317757   0.1367420   0.6837061   0.5495690
## 4   0.5685053   0.5429936   0.4392523   0.1367420   0.6853035   0.5528017
## 5   0.5667260   0.5429936   0.4355140   0.1367420   0.6853035   0.5528017
## 6   0.5685053   0.5429936   0.4355140   0.1367420   0.6853035   0.5538793
##   magnet_arm_x magnet_arm_y magnet_arm_z roll_dumbbell pitch_dumbbell
## 1    0.1581259    0.7476923    0.8621224     0.5427530      0.2645508
## 2    0.1573939    0.7476923    0.8597986     0.5430087      0.2640708
## 3    0.1581259    0.7548718    0.8597986     0.5420974      0.2652728
## 4    0.1551977    0.7548718    0.8590240     0.5439866      0.2648859
## 5    0.1537335    0.7476923    0.8543765     0.5438157      0.2647696
## 6    0.1573939    0.7528205    0.8597986     0.5438279      0.2634685
##   yaw_dumbbell total_accel_dumbbell gyros_dumbbell_x gyros_dumbbell_y
## 1    0.2158017             0.637931        0.9892348       0.03844732
## 2    0.2163356             0.637931        0.9892348       0.03844732
## 3    0.2149291             0.637931        0.9892348       0.03844732
## 4    0.2158027             0.637931        0.9892348       0.03844732
## 5    0.2158700             0.637931        0.9892348       0.03844732
## 6    0.2171388             0.637931        0.9892348       0.03844732
##   gyros_dumbbell_z accel_dumbbell_x accel_dumbbell_y accel_dumbbell_z
## 1      0.007451938        0.2828746        0.4682540       0.09662577
## 2      0.007451938        0.2844037        0.4682540       0.09969325
## 3      0.007451938        0.2859327        0.4662698       0.09815951
## 4      0.007389317        0.2859327        0.4702381       0.09969325
## 5      0.007451938        0.2844037        0.4702381       0.09815951
## 6      0.007451938        0.2828746        0.4702381       0.09969325
##   magnet_dumbbell_x magnet_dumbbell_y magnet_dumbbell_z roll_forearm
## 1        0.06801619         0.9196787         0.2759104    0.5788889
## 2        0.07125506         0.9203874         0.2773109    0.5786111
## 3        0.06639676         0.9208599         0.2787115    0.5786111
## 4        0.07368421         0.9220411         0.2829132    0.5780556
## 5        0.07206478         0.9194425         0.2717087    0.5777778
## 6        0.06882591         0.9199150         0.2745098    0.5775000
##   pitch_forearm yaw_forearm total_accel_forearm gyros_forearm_x gyros_forearm_y
## 1    0.05298829  0.07500000           0.3333333       0.8482865      0.02207408
## 2    0.05298829  0.07500000           0.3333333       0.8479014      0.02207408
## 3    0.05298829  0.07777778           0.3333333       0.8482865      0.02201119
## 4    0.05298829  0.07777778           0.3333333       0.8479014      0.02201119
## 5    0.05298829  0.07777778           0.3333333       0.8479014      0.02207408
## 6    0.05298829  0.07777778           0.3333333       0.8479014      0.02201119
##   gyros_forearm_z accel_forearm_x accel_forearm_y accel_forearm_z
## 1      0.03375298       0.7076923       0.5369775       0.3134328
## 2      0.03375298       0.7076923       0.5369775       0.3120760
## 3      0.03383663       0.7117949       0.5376206       0.3161465
## 4      0.03383663       0.7046154       0.5389068       0.3147897
## 5      0.03375298       0.7046154       0.5389068       0.3147897
## 6      0.03371115       0.7087179       0.5369775       0.3134328
##   magnet_forearm_x magnet_forearm_y magnet_forearm_z
## 1        0.6470287        0.6523569        0.7023752
## 2        0.6465164        0.6553030        0.7009210
## 3        0.6465164        0.6540404        0.6989821
## 4        0.6475410        0.6540404        0.6989821
## 5        0.6470287        0.6527778        0.7009210
## 6        0.6511270        0.6548822        0.7033446

Mantenemos una copia etiquetada de los datos normalizados, por si fuera necesaria más adelante.

classe <- df$classe
df_labelled_norm <- cbind(classe, df_norm)

rm(classe) # eliminamos el objeto classe, ya no es necesario

head(df_labelled_norm)
##   classe roll_belt pitch_belt  yaw_belt total_accel_belt gyros_belt_x
## 1      A 0.1587742  0.5501292 0.2384401        0.1034483    0.3190184
## 2      A 0.1587742  0.5501292 0.2384401        0.1034483    0.3251534
## 3      A 0.1588266  0.5501292 0.2384401        0.1034483    0.3190184
## 4      A 0.1591409  0.5499569 0.2384401        0.1034483    0.3251534
## 5      A 0.1591409  0.5501292 0.2384401        0.1034483    0.3251534
## 6      A 0.1589838  0.5500431 0.2384401        0.1034483    0.3251534
##   gyros_belt_y gyros_belt_z accel_belt_x accel_belt_y accel_belt_z
## 1     0.500000    0.4675325    0.4829268    0.3133047    0.7815789
## 2     0.500000    0.4675325    0.4780488    0.3133047    0.7815789
## 3     0.500000    0.4675325    0.4878049    0.3175966    0.7842105
## 4     0.500000    0.4642857    0.4780488    0.3090129    0.7789474
## 5     0.515625    0.4675325    0.4829268    0.3047210    0.7868421
## 6     0.500000    0.4675325    0.4829268    0.3133047    0.7789474
##   magnet_belt_x magnet_belt_y magnet_belt_z  roll_arm pitch_arm    yaw_arm
## 1    0.09124767     0.7680251     0.3384279 0.1444444 0.6277496 0.05277778
## 2    0.08379888     0.7962382     0.3406114 0.1444444 0.6277496 0.05277778
## 3    0.09310987     0.7711599     0.3471616 0.1444444 0.6277496 0.05277778
## 4    0.08566108     0.7836991     0.3417031 0.1444444 0.6254935 0.05277778
## 5    0.08566108     0.7711599     0.3504367 0.1444444 0.6254935 0.05277778
## 6    0.09683426     0.7805643     0.3395197 0.1444444 0.6249295 0.05277778
##   total_accel_arm gyros_arm_x gyros_arm_y gyros_arm_z accel_arm_x accel_arm_y
## 1       0.5076923   0.5667260   0.5477707   0.4317757   0.1379310   0.6821086
## 2       0.5076923   0.5685053   0.5445860   0.4317757   0.1355529   0.6837061
## 3       0.5076923   0.5685053   0.5445860   0.4317757   0.1367420   0.6837061
## 4       0.5076923   0.5685053   0.5429936   0.4392523   0.1367420   0.6853035
## 5       0.5076923   0.5667260   0.5429936   0.4355140   0.1367420   0.6853035
## 6       0.5076923   0.5685053   0.5429936   0.4355140   0.1367420   0.6853035
##   accel_arm_z magnet_arm_x magnet_arm_y magnet_arm_z roll_dumbbell
## 1   0.5528017    0.1581259    0.7476923    0.8621224     0.5427530
## 2   0.5506466    0.1573939    0.7476923    0.8597986     0.5430087
## 3   0.5495690    0.1581259    0.7548718    0.8597986     0.5420974
## 4   0.5528017    0.1551977    0.7548718    0.8590240     0.5439866
## 5   0.5528017    0.1537335    0.7476923    0.8543765     0.5438157
## 6   0.5538793    0.1573939    0.7528205    0.8597986     0.5438279
##   pitch_dumbbell yaw_dumbbell total_accel_dumbbell gyros_dumbbell_x
## 1      0.2645508    0.2158017             0.637931        0.9892348
## 2      0.2640708    0.2163356             0.637931        0.9892348
## 3      0.2652728    0.2149291             0.637931        0.9892348
## 4      0.2648859    0.2158027             0.637931        0.9892348
## 5      0.2647696    0.2158700             0.637931        0.9892348
## 6      0.2634685    0.2171388             0.637931        0.9892348
##   gyros_dumbbell_y gyros_dumbbell_z accel_dumbbell_x accel_dumbbell_y
## 1       0.03844732      0.007451938        0.2828746        0.4682540
## 2       0.03844732      0.007451938        0.2844037        0.4682540
## 3       0.03844732      0.007451938        0.2859327        0.4662698
## 4       0.03844732      0.007389317        0.2859327        0.4702381
## 5       0.03844732      0.007451938        0.2844037        0.4702381
## 6       0.03844732      0.007451938        0.2828746        0.4702381
##   accel_dumbbell_z magnet_dumbbell_x magnet_dumbbell_y magnet_dumbbell_z
## 1       0.09662577        0.06801619         0.9196787         0.2759104
## 2       0.09969325        0.07125506         0.9203874         0.2773109
## 3       0.09815951        0.06639676         0.9208599         0.2787115
## 4       0.09969325        0.07368421         0.9220411         0.2829132
## 5       0.09815951        0.07206478         0.9194425         0.2717087
## 6       0.09969325        0.06882591         0.9199150         0.2745098
##   roll_forearm pitch_forearm yaw_forearm total_accel_forearm gyros_forearm_x
## 1    0.5788889    0.05298829  0.07500000           0.3333333       0.8482865
## 2    0.5786111    0.05298829  0.07500000           0.3333333       0.8479014
## 3    0.5786111    0.05298829  0.07777778           0.3333333       0.8482865
## 4    0.5780556    0.05298829  0.07777778           0.3333333       0.8479014
## 5    0.5777778    0.05298829  0.07777778           0.3333333       0.8479014
## 6    0.5775000    0.05298829  0.07777778           0.3333333       0.8479014
##   gyros_forearm_y gyros_forearm_z accel_forearm_x accel_forearm_y
## 1      0.02207408      0.03375298       0.7076923       0.5369775
## 2      0.02207408      0.03375298       0.7076923       0.5369775
## 3      0.02201119      0.03383663       0.7117949       0.5376206
## 4      0.02201119      0.03383663       0.7046154       0.5389068
## 5      0.02207408      0.03375298       0.7046154       0.5389068
## 6      0.02201119      0.03371115       0.7087179       0.5369775
##   accel_forearm_z magnet_forearm_x magnet_forearm_y magnet_forearm_z
## 1       0.3134328        0.6470287        0.6523569        0.7023752
## 2       0.3120760        0.6465164        0.6553030        0.7009210
## 3       0.3161465        0.6465164        0.6540404        0.6989821
## 4       0.3147897        0.6475410        0.6540404        0.6989821
## 5       0.3147897        0.6470287        0.6527778        0.7009210
## 6       0.3134328        0.6511270        0.6548822        0.7033446

Recordemos que cada observación del dataset corresponde a una postura durante la realización de un ejercicio. El objetivo es construir y explorar modelos de segmentación que intenten capturar la estructura de grupos existente en el conjunto de datos.

6.1 Clustering Jerárquico (agglomerative clustering)

Implementamos clustering jerárquico utilizando la función hclust(), que forma parte del paquete stats que se carga por defecto.

Utilizamos la distancia de Ward, aunque es posible utilizar otro métodos como “single”, “complete”, “average”, etc

hclust.result <- hclust(dist(df_norm), method="ward.D")
plot(hclust.result, labels=df_labelled_norm$classe) # añadimos etiquetas de classe

El número de observaciones es muy elevado, por lo que es normal que no podamos visualizar el detalle de cada observación y su etiqueta. Sin embargo, podremos apreciar la estructura jerárquica del clustering.

Visualmente, podemos seleccionar el número de clúster, por ejemplo:

  • Cuatro clústers:
plot(hclust.result, labels=df_labelled_norm$classe) # añadimos etiquetas de classe
rect.hclust(hclust.result, 4)

  • Cinco clústers:
plot(hclust.result, labels=df_labelled_norm$classe) # añadimos etiquetas de classe
rect.hclust(hclust.result, 5)

  • Seis clústers:
plot(hclust.result, labels=df_labelled_norm$classe) # añadimos etiquetas de classe
rect.hclust(hclust.result, 6)

Podemos podar el árbol obtenido, limitando el número de clúster “k” o la altura “h”. Utilizamos la función cutree(), que devuelve un vector con la asignación de cada observación a un clúster.

Probamos con k= 5 clústers

cut_avg <- cutree(hclust.result, k = 5)
cut_avg[1:10]
##  1  2  3  4  5  6  7  8  9 10 
##  1  1  1  1  1  1  1  1  1  1

Añadimos la información de pertenencia a cada clúster. Contamos el número de instancias en cada clúster

df_norm_hclust <- df_norm %>% mutate(cluster = cut_avg)
df_norm_hclust %>% count(cluster)
## # A tibble: 5 x 2
##   cluster     n
##     <int> <int>
## 1       1  6641
## 2       2  2610
## 3       3  3892
## 4       4  3536
## 5       5  2943

Comprobamos contra las etiquetas de clase:

table(df_norm_hclust$cluster, df_labelled_norm$classe)
##    
##        A    B    C    D    E
##   1 1745 1438 1004 1181 1273
##   2  640  505  499  469  497
##   3 1165  776  750  515  686
##   4  899  745  539  642  711
##   5 1131  333  630  409  440

Podemos observar que los clústers hallados mediantes técnicas no supervisadas no coinciden con las etiquetas de clase. Recordemos que, mientras que un modelo de clasificación supervisada es entrenado sobre datos etiquetados y su salida corresponde a los valores de las clases aprendidas, los modelos no supervisados no asumen un número de clases a priori. El modelo de clustering jerárquico estudia la distribución de los datos y trata de identificar grupos según una medida dada de distancia.

Otra opción es seleccionar variables específicas y realizar el clustering sobre estas variables.

Estudiando la matriz de correlaciones, observamos que las variables “magnet_belt_y”, “magnet_belt_z” están correladas con la clase E, mientras que “pitch_forearm” está correlada con la clase D. Si seleccionamos estas columnas, podemos estudiar la correspondencia entre el clustering realizado por hclust() y las etiquetas reales

hclust.result <- hclust(dist(df_norm[colnames(df_norm) %in% c("magnet_belt_y", "magnet_belt_z", "pitch_forearm")]),
                        method="ward.D")
plot(hclust.result, labels=df_labelled_norm$classe) # añadimos etiquetas de classe

Podemos podar el árbol obtenido, limitando el número de clúster “k” o la altura “h”. Utilizamos la función cutree(), que devuelve un vector con la asignación de cada observación a un clúster.

De nuevo, probamos con k = 5 clusters:

cut_avg <- cutree(hclust.result, k = 5)
cut_avg[1:10]
##  1  2  3  4  5  6  7  8  9 10 
##  1  1  1  1  1  1  1  1  1  1

Contamos el número de instancias en cada clúster

df_norm_hclust <- df_norm %>% mutate(cluster = cut_avg)
df_norm_hclust %>% count(cluster)
## # A tibble: 5 x 2
##   cluster     n
##     <int> <int>
## 1       1  1414
## 2       2  3769
## 3       3  5024
## 4       4  8298
## 5       5  1117

Comprobamos contra las etiquetas reales:

table(df_norm_hclust$cluster, df_labelled_norm$classe)
##    
##        A    B    C    D    E
##   1 1414    0    0    0    0
##   2  983  801  770  199 1016
##   3  847  950  809 1626  792
##   4 2336 2046 1843 1155  918
##   5    0    0    0  236  881

Sobre el subconjunto de variables seleccionado, el algoritmo de clustering identifica un clúster formado únicamente por observaciones correspondientes a la clase A y un clúster formado por observaciones de las clase D y E. Los demás clusters contienen observaciones de todas las clases.

6.2 Clustering con K-means (centroid-based clustering)

En esta sección, utilizamos el algoritmo k-means, buscando calcular el mejor clustering a partir de los datos. Para determinar el número óptimo de clusters, podemos seguir dos aproximaciones:

  • Utilizar la función fviz_nbclust para determinar y visualizar el número óptimo de clústers, usando diferentes métodos: “within-groups sums of squares” (wss) y buscar el “codo” de la curva, average silhouette o gap statistics.

  • Usar alguna de las medidas de calidad de clusters, o todas ellas, mediante el paquete NbClust. Podemos pintar el resultado de esta función como un diagrama de barras para verlo gráficamente.

6.2.1 fviz_nbclust

Calculamos el wss y representamos la curva de codo para ver qué número de clusters nos sugiere.

Recordemos que en k=1 existe un único clúster y la wss es máxima, mientras que en k=inf todos los puntos pertenecen a su propio clúster y el wss es cero. La curva desciende rápidamente hasta que el número de clústers alcanza el número de agrupaciones en la distribución de datos.

Nota: recuerda que esta metrica se basa en un cambio abrupto en la curva, lo cual es subjetivo.

Observamos que en k=2, k=4 y k=6 se suaviza la caída de manera apreciable. Entre k=8 y k=9 la wss incluso aumenta.

gc() #provoca recolección de basura, liberando memoria
##           used  (Mb) gc trigger   (Mb)  max used   (Mb)
## Ncells 2908841 155.4    5014097  267.8   5014097  267.8
## Vcells 7143520  54.6  563040517 4295.7 590750474 4507.1
fviz_nbclust(df_norm, kmeans, k.max = 15, method = "wss") +
  geom_vline(xintercept = 4, linetype = 2)

Utilizamos ahora el indicador average silhouette. Según esta métrica, el número óptimo de clústers es 14. Si nos limitamos a valores de k menores de 8, los valores k=2 y k=5 son los mejores candidatos.

gc() #provoca recolección de basura, liberando memoria
##           used  (Mb) gc trigger    (Mb)   max used    (Mb)
## Ncells 3087205 164.9    5014097   267.8    5014097   267.8
## Vcells 7388243  56.4 1607864784 12267.1 2081448468 15880.2
fviz_nbclust(df_norm, kmeans, k.max = 15, method = "silhouette")

Los resultados no son definitivos, por lo que pasamos a evaluar múltiples métricas utilizando el paquete NbClust.

6.2.2 NbClust

Calculamos el número óptimo de clusters utilizando el paquete NbClust.

NbClust provee 30 índices para determinar el número de clústers y propone al usuario el mejor esquema de clústering. Fijamos el mínimo número de clústers a 2 y el máximo número de clústers a 15 (valores por defecto).

Es importante destacar que NbClust consume mucha memoria, y en datasets relativamente grandes como el nuestro la ejecución puede fallar con error “Error: cannot allocate vector of size XX”, donde XX es el tamaño del vector. Hemos eliminado los índices que más memoria utilizan y conseguido que la ejecución finalice con éxito. Los índices eliminados son: “silhouette”, “ptbiserial”, “gap”, “frey”, “mcclain”, “gamma”, “gplus”, “tau”, “hubert”.

Como la función NbClust no permite ejecutar un conjunto personalizado de índices (o todos o uno en particular) tendremos que recorrer la lista de índices manualmente y recopilar la información nosotros.

Finalmente, procedemos a mostrar un resumen del número de índices que han escogido cada número de clusters y a representar esta misma información gráficamente.

gc() #provoca recolección de basura, liberando memoria al reclamar memoria ocupada por objetos que no están ya en uso
##           used  (Mb) gc trigger   (Mb)   max used    (Mb)
## Ncells 3088939 165.0    5014097  267.8    5014097   267.8
## Vcells 7395212  56.5 1286291828 9813.7 2081448468 15880.2
# indices <- c("kl", "ch", "hartigan", "ccc", "scott", "marriot", "trcovw", "tracew", "friedman", "rubin", "cindex", "db", "silhouette", "duda", "pseudot2", "beale", "ratkowsky", "ball", "ptbiserial", "gap", "frey", "mcclain", "gamma", "gplus", "tau", "dunn", "hubert", "sdindex", "dindex", "sdbw")
# indices <- c("gamma", "gplus", "tau")

indices <- c("kl", "ch", "hartigan", "ccc", "scott", "marriot", "trcovw", "tracew", "friedman", "rubin", "cindex", "db", "duda", "pseudot2", "beale", "ratkowsky", "ball", "dunn", "sdindex", "dindex", "sdbw")

best_clusters <- rep(0, 15)

for (i in 1:length(indices)) {
  print(indices[i])
  nc <- NbClust(df_norm, min.nc=2, max.nc=15, method="kmeans", index=indices[i])
  best_clusters[nc$Best.nc[1]]=best_clusters[nc$Best.nc[1]]+1
  print("índice completado")
}
## [1] "kl"
## [1] "índice completado"
## [1] "ch"
## [1] "índice completado"
## [1] "hartigan"
## [1] "índice completado"
## [1] "ccc"
## [1] "índice completado"
## [1] "scott"
## [1] "índice completado"
## [1] "marriot"
## [1] "índice completado"
## [1] "trcovw"
## [1] "índice completado"
## [1] "tracew"
## [1] "índice completado"
## [1] "friedman"
## [1] "índice completado"
## [1] "rubin"
## [1] "índice completado"
## [1] "cindex"
## [1] "índice completado"
## [1] "db"
## [1] "índice completado"
## [1] "duda"
## [1] "índice completado"
## [1] "pseudot2"
## [1] "índice completado"
## [1] "beale"
## [1] "índice completado"
## [1] "ratkowsky"
## [1] "índice completado"
## [1] "ball"
## [1] "índice completado"
## [1] "dunn"
## [1] "índice completado"
## [1] "sdindex"
## [1] "índice completado"
## [1] "dindex"

## *** : The D index is a graphical method of determining the number of clusters. 
##                 In the plot of D index, we seek a significant knee (the significant peak in Dindex
##                 second differences plot) that corresponds to a significant increase of the value of
##                 the measure. 
##  
## [1] "índice completado"
## [1] "sdbw"
## [1] "índice completado"
print(best_clusters)
##  [1] 0 2 6 1 2 3 0 0 3 0 0 0 0 1 2
par(mfrow = c(1, 1))
barplot(best_clusters, xlab="Numer of Clusters", ylab="Number of Criteria", main="Number of Clusters Chosen by 21 Criteria", names.arg = 1:15)

Observamos que la mayoría de índices optan por 3 clústers, por lo que tomaremos este valor como referencia.

Calculemos k-means con el número óptimo de clusters: k=3. Utilizamos el parámetro nstart para seleccionar el número de veces que el algoritmo debe escoger los centroides iniciales. Esto alivia el problema de inicialización del algoritmo y lo hace más robusto.

nClusters <- 3
fit.km <- kmeans(df_norm, nClusters, nstart=25)

print(fit.km$centers)
##   roll_belt pitch_belt  yaw_belt total_accel_belt gyros_belt_x gyros_belt_y
## 1 0.7978260  0.6520883 0.5127548        0.6569510    0.2815004    0.5413976
## 2 0.8233997  0.1240591 0.9380867        0.6251462    0.3546263    0.5865738
## 3 0.1546993  0.5208422 0.2528657        0.1235033    0.3251057    0.5016165
##   gyros_belt_z accel_belt_x accel_belt_y accel_belt_z magnet_belt_x
## 1    0.3814798    0.4422150    0.5736548    0.2712299     0.1262086
## 2    0.4190589    0.8242887    0.4817486    0.2905738     0.4165408
## 3    0.4689231    0.5242650    0.3077671    0.7985950     0.1601507
##   magnet_belt_y magnet_belt_z  roll_arm pitch_arm   yaw_arm total_accel_arm
## 1     0.7199881     0.2875618 0.4890390 0.4559008 0.4702986       0.3371899
## 2     0.7599030     0.3270579 0.4563814 0.5301997 0.4268976       0.3266345
## 3     0.7679649     0.3030659 0.6261450 0.4644918 0.5452143       0.4230946
##   gyros_arm_x gyros_arm_y gyros_arm_z accel_arm_x accel_arm_y accel_arm_z
## 1   0.5683900   0.4858289   0.5209275   0.5126318   0.4339582   0.6825509
## 2   0.5880723   0.4611194   0.5745281   0.3717211   0.4061243   0.6362067
## 3   0.5647813   0.5388690   0.4274139   0.3571728   0.7034369   0.5499090
##   magnet_arm_x magnet_arm_y magnet_arm_z roll_dumbbell pitch_dumbbell
## 1    0.5971574    0.5693306    0.7079904     0.4528123      0.5050067
## 2    0.5943772    0.5593807    0.7054973     0.7010448      0.4237197
## 3    0.5383430    0.5597514    0.6923120     0.6080415      0.4546090
##   yaw_dumbbell total_accel_dumbbell gyros_dumbbell_x gyros_dumbbell_y
## 1    0.7045686            0.1269567        0.9901853       0.04019575
## 2    0.2080208            0.3174460        0.9899282       0.04020019
## 3    0.4849341            0.2739246        0.9899429       0.03911412
##   gyros_dumbbell_z accel_dumbbell_x accel_dumbbell_y accel_dumbbell_z
## 1      0.007020904        0.6436975        0.3456884        0.5781482
## 2      0.007165380        0.5827837        0.5808557        0.3088489
## 3      0.007017842        0.5726590        0.5240091        0.4322940
##   magnet_dumbbell_x magnet_dumbbell_y magnet_dumbbell_z roll_forearm
## 1         0.4829099         0.8530606         0.2611368    0.5800866
## 2         0.1139064         0.9252548         0.4458319    0.5000000
## 3         0.1654710         0.9252940         0.5348229    0.6410185
##   pitch_forearm yaw_forearm total_accel_forearm gyros_forearm_x gyros_forearm_y
## 1     0.6045025   0.4614358           0.2928418       0.8481614      0.02208778
## 2     0.4467036   0.5000000           0.3781023       0.8842938      0.02384698
## 3     0.4805640   0.6339669           0.3167654       0.8438315      0.02182931
##   gyros_forearm_z accel_forearm_x accel_forearm_y accel_forearm_z
## 1      0.03384744       0.3556169       0.4537660       0.5154201
## 2      0.03587553       0.3624194       0.6074771       0.5957017
## 3      0.03429686       0.5410481       0.5099078       0.5129412
##   magnet_forearm_x magnet_forearm_y magnet_forearm_z
## 1        0.4419144        0.5338565        0.7033260
## 2        0.4945784        0.5577800        0.7223659
## 3        0.5304557        0.5307534        0.6118853

Recordemos que cada observación corresponde a una postura durante la realización del ejercicio. Hemos agrupado las posturas en tres grupos, caracterizados por la media de cada variable en ese grupo (“Cluster means”)

Realizamos un análisis de componentes principales sobre nuestros datos de entrada

pca <- prcomp(df_norm, scale. = T, center = T)
summary(pca)
## Importance of components:
##                           PC1    PC2     PC3     PC4     PC5     PC6     PC7
## Standard deviation     2.8908 2.8466 2.16241 2.03215 1.91101 1.73308 1.49665
## Proportion of Variance 0.1607 0.1558 0.08992 0.07942 0.07023 0.05776 0.04308
## Cumulative Proportion  0.1607 0.3165 0.40646 0.48587 0.55610 0.61386 0.65694
##                            PC8     PC9    PC10    PC11    PC12    PC13    PC14
## Standard deviation     1.43973 1.31043 1.22834 1.17707 1.06266 0.99331 0.94377
## Proportion of Variance 0.03986 0.03302 0.02902 0.02664 0.02172 0.01897 0.01713
## Cumulative Proportion  0.69680 0.72983 0.75884 0.78549 0.80720 0.82618 0.84331
##                           PC15    PC16    PC17    PC18    PC19    PC20    PC21
## Standard deviation     0.91436 0.88840 0.82337 0.78085 0.72968 0.69631 0.65241
## Proportion of Variance 0.01608 0.01518 0.01304 0.01173 0.01024 0.00932 0.00819
## Cumulative Proportion  0.85938 0.87456 0.88760 0.89932 0.90956 0.91889 0.92707
##                           PC22    PC23    PC24    PC25    PC26    PC27    PC28
## Standard deviation     0.63134 0.61862 0.58250 0.55471 0.54126 0.50596 0.48606
## Proportion of Variance 0.00767 0.00736 0.00653 0.00592 0.00563 0.00492 0.00454
## Cumulative Proportion  0.93474 0.94210 0.94862 0.95454 0.96017 0.96510 0.96964
##                           PC29    PC30    PC31    PC32    PC33    PC34    PC35
## Standard deviation     0.45105 0.42413 0.41245 0.36296 0.34904 0.33533 0.30328
## Proportion of Variance 0.00391 0.00346 0.00327 0.00253 0.00234 0.00216 0.00177
## Cumulative Proportion  0.97355 0.97701 0.98028 0.98282 0.98516 0.98732 0.98909
##                           PC36    PC37    PC38    PC39    PC40    PC41    PC42
## Standard deviation     0.28235 0.25340 0.23778 0.23492 0.20199 0.19520 0.18830
## Proportion of Variance 0.00153 0.00123 0.00109 0.00106 0.00078 0.00073 0.00068
## Cumulative Proportion  0.99062 0.99186 0.99295 0.99401 0.99479 0.99553 0.99621
##                           PC43    PC44    PC45    PC46    PC47   PC48    PC49
## Standard deviation     0.18365 0.17949 0.16946 0.16387 0.14718 0.1435 0.11607
## Proportion of Variance 0.00065 0.00062 0.00055 0.00052 0.00042 0.0004 0.00026
## Cumulative Proportion  0.99686 0.99748 0.99803 0.99854 0.99896 0.9994 0.99962
##                           PC50    PC51    PC52
## Standard deviation     0.10897 0.07721 0.04636
## Proportion of Variance 0.00023 0.00011 0.00004
## Cumulative Proportion  0.99984 0.99996 1.00000

Observamos que las dos primeras componentes proporcionan algo más del 30% de la información del conjunto.

Aplicamos una transformación en componentes principales, rotando el espacio de variables originales a las componentes principales. Adicionalmente, añadimos la etiqueta de cada clúster:

new_features <- predict(pca, newdata = df_norm)

pca.dat <- as.data.frame(cbind(new_features, group=fit.km$cluster))

Visualizamos los datos. Para añadir interactividad a los gráficos, usamos la biblioteca ggplotly, que nos permite acceder a información adicional al posicionarnos sobre un punto de interés.

gg2 <- ggplot(pca.dat) +
  geom_point(aes(x=PC1, y=PC2, col=factor(group), text=rownames(pca.dat)), size=2) +
  labs(title = "Visualizing K-Means Clusters Against First Two Principal Components") +
  scale_color_brewer(name="", palette = "Set1")
## Warning: Ignoring unknown aesthetics: text
ggplotly(gg2, tooltip = c("text", "x", "y")) %>%
  layout(legend = list(x=.9, y=.99))

Observamos que los tres clústers aparecen bien diferenciados.

Aunque el número óptimo de clústers fue k=3, observamos que, proyectando sobre las dos primeras componentes principales, parece que el clúster número uno se podría separar en dos subgrupos.

Podemos incluso representar los datos en 3D, utilizando las tres primeras componentes principales, que proporcionan algo más del 40% de la información del conjunto.

fig <- plot_ly(x= pca.dat$PC1, y= pca.dat$PC2 , z= pca.dat$PC3, type="scatter3d", mode="markers", color=factor(pca.dat$group), colors=c('red2', 'blue2', 'green3'))

fig <- fig %>% layout(title = 'Visualizing K-Means Clusters Against First Three Principal Components',
  scene = list(xaxis = list(title = 'PC1'), yaxis = list(title = 'PC2'), zaxis = list(title = 'PC3')))

fig

Podemos confirmar que los clúster 1 y 3 tienen puntos cercanos, que pueden ser problemáticos a la hora de ser asignados. Sin embargo, los resultados de k-means son muy buenos.

La representación en 3D nos permite observar un punto perteneciente al clúster 3 muy alejado de los demás puntos, que probablemente debería ser tratado en la fase de preprocesado, ya que puede afectar a la bondad del clustering.

Por último, podemos estudiar en profundidad el dataset, caracterizando cada clúster según el contexto y objetivo de negocio. Para ello, puede ser útil seleccionar las variables originales con mayor relevancia para nuestro problema y estudiar como se distribuyen en cada clúster, calculando sus estadísticos.

También podemos pintar los clusters únicamente con dos coordenadas, por ejemplo:

plot(df_norm[,c(2,5)], col = fit.km$cluster)

y finalmente podemos comparar contra las etiquetas de clase del dataset etiquetado, para entender qué composición de clases tiene cada clúster

df_norm_hclust_label <- as.data.frame(cbind(df_labelled_norm, group=fit.km$cluster))

df_norm_hclust_label %>%
  group_by(group, classe) %>%
  count(classe) %>%
  group_by(group) %>%
  mutate(classe_perc = round(n/sum(n)*100, 2)) %>%
  distinct(group, classe, classe_perc)
## # A tibble: 15 x 3
## # Groups:   group [3]
##    group classe classe_perc
##    <int> <fct>        <dbl>
##  1     1 A             25.0
##  2     1 B             20.3
##  3     1 C             16.9
##  4     1 D             18.1
##  5     1 E             19.7
##  6     2 A             29.9
##  7     2 B             19.9
##  8     2 C             19.3
##  9     2 D             13.2
## 10     2 E             17.6
## 11     3 A             30.0
## 12     3 B             18.5
## 13     3 C             17.0
## 14     3 D             16.6
## 15     3 E             17.9

o cómo se reparten las clases en cada grupo

df_norm_hclust_label <- as.data.frame(cbind(df_labelled_norm, group=fit.km$cluster))


df_norm_hclust_label %>%
  group_by(classe, group) %>%
  count(group) %>%
  group_by(classe) %>%
  mutate(group_perc = round(n/sum(n)*100, 2)) %>%
  distinct(classe, group, group_perc)
## # A tibble: 15 x 3
## # Groups:   classe [5]
##    classe group group_perc
##    <fct>  <int>      <dbl>
##  1 A          1       27.6
##  2 A          2       20.9
##  3 A          3       51.5
##  4 B          1       32.9
##  5 B          2       20.4
##  6 B          3       46.6
##  7 C          1       30.3
##  8 C          2       21.9
##  9 C          3       47.8
## 10 D          1       34.6
## 11 D          2       16.0
## 12 D          3       49.4
## 13 E          1       33.5
## 14 E          2       19.0
## 15 E          3       47.5

Concluímos que los clústers contienen una mezcla de las 5 etiquetas del dataset inicial.

6.3 Clustering con K-medoids (medoid-based clustering)

Aplicamos ahora el algoritmo K-medoids. En particular, utilizamos dos métodos:

  • k-medoids dado el número de clústers óptimo encontrado en la sección anterior
  • k-medoids estimando automáticamente el número de clústers

K-medoids un algoritmo muy similar al k-means. La principal diferencia es que se usa el punto más cercano al centroide como representante del cluster, lo que hace que k-medoids sea más robusto que k-means cuando el dataset contiene outliers.

Nota: medoide es un concepto similar a centroide, pero los medoides siempre están restringidos a ser miembros del conjunto de datos.

Utilizamos PAM (Partition Around Medoids) del paquete cluster. Para evaluar el número de clúster, utilizaremos la métrica silhouette. El valor de la anchura de silhouette se interpreta como sigue:

  • Valores cercanos a 1 sugieren que la observación se identifica con el clúster asignado
  • Valores cercanos a 0 sugieren que la observación está entre dos clústers
  • Valores cercanos a -1 sugieren que la observación no se identifica con el clúster asignado

La implementación de PAM provee la anchura de silhouette media por clúster y total.

6.3.1 Número de clústers fijado

Calculamos el clustering fijando el número de clusters k=3

pam.result<-pam(df_norm, k=3)

Representamos gráficamente:

layout(matrix(c(1,2), 1, 2))
plot(pam.result)

layout(matrix(1))

Observamos que, utilizando k-medoids, el clúster etiquetado como número 2 no está muy diferenciado de los demás. El índice de anchura de silhouette indica que el clúster no está bien diferenciado.

Vamos a confirmar este punto. Llevamos a cabo un análisis de componentes principales y usamos las dos primeras para visualizar los datos.

#new_features <- predict(pca, newdata = df_norm) #No es necesario volver a ejecutar esta línea, es solo informativa

pca.dat <- as.data.frame(cbind(new_features, group=pam.result$clustering))

Visualizamos los datos. Para añadir interactivdad a los gráficos, usamos la biblioteca ggplotly, que nos permite acceder a información adicional al posicionarnos sobre un punto de interés.

gg2 <- ggplot(pca.dat) +
  geom_point(aes(x=PC1, y=PC2, col=factor(group), text=rownames(pca.dat)), size=2) +
  labs(title = "Visualizing K-Means Clusters Against First Two Principal Components") +
  scale_color_brewer(name="", palette = "Set1")
## Warning: Ignoring unknown aesthetics: text
ggplotly(gg2, tooltip = c("text", "x", "y")) %>%
  layout(legend = list(x=.9, y=.99))

Podemos incluso representar los datos en 3D, utilizando las tres primeras componentes principales, que proporcionan algo más del 40% de la información del conjunto.

fig <- plot_ly(x= pca.dat$PC1, y= pca.dat$PC2 , z= pca.dat$PC3, type="scatter3d", mode="markers", color=factor(pca.dat$group), colors=c('red2', 'blue2', 'green3'))

fig <- fig %>% layout(title = 'Visualizing K-Means Clusters Against First Three Principal Components',
  scene = list(xaxis = list(title = 'PC1'), yaxis = list(title = 'PC2'), zaxis = list(title = 'PC3')))

fig

Efectivamente, confirmamos que el clúster 2 (en azul) se mezcla con el clúster 1 y el clúster 3. En el grupo de observaciones del clúster 1 aparece múltiples puntos asignado al clúster 2, y en el grupo de observaciones del clúster 2 aparecen múltiples puntos asignados al clúster 3.

Podemos probar a ejercutar el modelo de nuevo, fijando el número de clusters k=4

pam.result<-pam(df_norm, k=4)

Representamos gráficamente:

layout(matrix(c(1,2), 1, 2))
plot(pam.result)

layout(matrix(1))

Observamos que sigue existiendo mezcla: el índice para los clústers 1 y 3 sigue siendo muy bajo, aunque la media del índice para todos los clústers mejora ligeramente.

6.3.2 Cálculo automático del número de clústers

Utilizando pamk, podemos calcular el clustering sin fijar el número de clústers. El parámetro krange determina el número de clústers a estimar, por defecto toma el valor de 2 a 10.

pamk.result<-pamk(df_norm, krange=2:10)

Representamos graficamente

layout(matrix(c(1,2), 1, 2))
plot(pamk.result$pamobject)

layout(matrix(1))

El algoritmo determina que k=2 es el número óptimo de clústers. Este número probablemente es demasiado pequeño para ser de utilidad real, ya que solo permite clasificar de manera binaria.

Probemos a fijar el parámetro krange como 3:10, evaluando únicamente un número de clústers entre 3 y 10.

pamk.result<-pamk(df_norm, krange=3:10)

Representamos graficamente

layout(matrix(c(1,2), 1, 2))
plot(pamk.result$pamobject)

layout(matrix(1))

En este caso, PAM determina que existen 5 clústers. El valor medio de la anchura de silhouette es similar al del caso anterior, aunque podemos ver que el valor del índice para el clúster 5 es bastante bajo.

De nuevo, llevamos a cabo un análisis de componentes principales y usamos las dos primeras para visualizar los datos.

#new_features <- predict(pca, newdata = df_norm) #No es necesario volver a ejecutar esta línea, es solo informativa

pca.dat <- as.data.frame(cbind(new_features, group=pamk.result$pamobject$clustering))

Visualizamos los datos. Para añadir interactivdad a los gráficos, usamos la biblioteca ggplotly, que nos permite acceder a información adicional al posicionarnos sobre un punto de interés.

gg2 <- ggplot(pca.dat) +
  geom_point(aes(x=PC1, y=PC2, col=factor(group), text=rownames(pca.dat)), size=2) +
  labs(title = "Visualizing K-Means Clusters Against First Two Principal Components") +
  scale_color_brewer(name="", palette = "Set1")
## Warning: Ignoring unknown aesthetics: text
ggplotly(gg2, tooltip = c("text", "x", "y")) %>%
  layout(legend = list(x=.9, y=.99))

Podemos incluso representar los datos en 3D, utilizando las tres primeras componentes principales, que proporcionan algo más del 40% de la información del conjunto.

fig <- plot_ly(x= pca.dat$PC1, y= pca.dat$PC2 , z= pca.dat$PC3, type="scatter3d", mode="markers", color=factor(pca.dat$group), colors=c('red2', 'blue2', 'green3', 'magenta2', 'orange'))

fig <- fig %>% layout(title = 'Visualizing K-Means Clusters Against First Three Principal Components',
  scene = list(xaxis = list(title = 'PC1'), yaxis = list(title = 'PC2'), zaxis = list(title = 'PC3')))

fig

Observamos que, proyectando sobre las tres primeras componentes principales, la separación de las observaciones en 5 grupos utilizando k-medoids no produce buenos resultados. Observaciones asignadas a distintos clúster se entremezclan y parece que el algoritmo tiene problemas para asignar los puntos correctamente.

Recordemos que estamos proyectando únicamente sobre 3 componentes, que proporcionan alrededor del 40 % de la información, por lo que existe pérdida de información. Sin embargo, después de ejecutar k-medoids con distinto número de clústers, estudiando el índice de silhouette y la proyección sobre las primeras componentes principales para cada uno de los modelos, podemos concluir que, en comparación, k-means produjo mejores resultados sobre nuestro dataset. En nuestro caso, los modelos de clustering basados en centroides funcionan mejor que los modelos basados en medoides.

Finalmente podemos estudiar cómo se distribuyen las clases para k-medoids con k=5

df_norm_hclust_label <- as.data.frame(cbind(df_labelled_norm, group=pamk.result$pamobject$clustering))

df_norm_hclust_label %>%
  group_by(classe, group) %>%
  count(group) %>%
  group_by(classe) %>%
  mutate(group_perc = round(n/sum(n)*100, 2)) %>%
  distinct(classe, group, group_perc)
## # A tibble: 25 x 3
## # Groups:   classe [5]
##    classe group group_perc
##    <fct>  <int>      <dbl>
##  1 A          1       40.1
##  2 A          2       11.4
##  3 A          3       16.2
##  4 A          4       20.9
##  5 A          5       11.4
##  6 B          1       24.8
##  7 B          2       12.6
##  8 B          3       20.3
##  9 B          4       20.0
## 10 B          5       22.3
## # ... with 15 more rows

De nuevo, cada clúster contiene representantes de todas las clases.

6.4 Expectation-Maximization (distribution-based clustering)

En esta sección implementamos el algoritmo Expectation-Maximization (EM). Este algoritmo intenta aprender la distribución de los datos de cada conjunto, estudiando:

  • La media
  • La desviación de la distribución (normal)

Existentes distintas variantes, en función de los grados de libertad de las distribuciones:

  • Deviación típica común (conjuntos esféricos)
  • Matriz de covarianza (conjuntos elipsoidales)

Por último, la pertenencia de un punto a un conjunto se expresa en términos de probabilidad.

Utilizamos el paquete Mclust, que implementa el algoritmo EM. Permite ajustar distintos tipos de distribuciónes y puede evaluar simultáneamente distintos números de clústers y devolver el más apropiado de acuerdo a una medida.

El parámetro “G” toma un entero o vector de enteros con el número de clústers que desea probar. Por defecto, toma el valor G=1:9 y prueba todos estos modelos

Mclust.result <- Mclust(df_norm) # si no especificas hace 1 a 9 clústers, y todos los posibles modelos

Podemos pintar la gráfica de evolución del BIC (Bayesian Information Criterion) para ver qué modelo se ajusta mejor.

# Notar que la interpretación del BIC en R es al revés de la interp. en Python
## En R: el más positvo, en Python el más negativo
plot(Mclust.result, data=df_norm, what="BIC")

summary(Mclust.result$BIC)
## Best BIC values:
##            VEV,9     VEV,8     VEV,7
## BIC      4574406 4414323.8 4369613.8
## BIC diff       0 -160082.4 -204792.5

El mejor modelo es VEV (distribución elipsoidal, volumen variable, misma forma, orientación variable) con 9 clústers, aunque los resultados con 7 y 8 clústers también son buenos.

El modelo EEV (distribución elipsoidal, mismo volumen, misma forma, orientación variable) también produce buenos resultados, aunque ligeramente peores que VEV. Los modelos con distribución elipsoidal son los que mejores resultados producen.

Utilizamos el mejor modelo: VEV con 9 clústers. Podemos obtener la asignación de cada observación a uno de los 9 clúster (hard prediction):

head(Mclust.result$classification, 5)
## 1 2 3 4 5 
## 4 4 4 4 4

o la probabilidad de que cada observación pertenezca a un cluster (soft prediction):

head(round(Mclust.result$z, 2), 5)
##   [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## 1    0    0    0    1    0    0    0    0    0
## 2    0    0    0    1    0    0    0    0    0
## 3    0    0    0    1    0    0    0    0    0
## 4    0    0    0    1    0    0    0    0    0
## 5    0    0    0    1    0    0    0    0    0

Podemos visualizar los clusters como una matrix de scatter plot, para cada combinación de variables. Por ejemplo, para las 4 primeras columnas:

plot(Mclust.result, dimens = 1:4, what="classification")

También podemos representar la densidad estimada

plot(Mclust.result, dimens = 1:4, what="density")

plot(Mclust.result, dimens = 4:5, what = "density", type = "persp")

y representar la incertidumbre en la clasificación

plot(Mclust.result, dimens = 1:4, what="uncertainty")

Por último, podemos llevar a cabo un análisis de componentes principales y usar las dos primeras para visualizar los datos. Utilizamos la descomposición realizada en las secciones anteriores

summary(pca)
## Importance of components:
##                           PC1    PC2     PC3     PC4     PC5     PC6     PC7
## Standard deviation     2.8908 2.8466 2.16241 2.03215 1.91101 1.73308 1.49665
## Proportion of Variance 0.1607 0.1558 0.08992 0.07942 0.07023 0.05776 0.04308
## Cumulative Proportion  0.1607 0.3165 0.40646 0.48587 0.55610 0.61386 0.65694
##                            PC8     PC9    PC10    PC11    PC12    PC13    PC14
## Standard deviation     1.43973 1.31043 1.22834 1.17707 1.06266 0.99331 0.94377
## Proportion of Variance 0.03986 0.03302 0.02902 0.02664 0.02172 0.01897 0.01713
## Cumulative Proportion  0.69680 0.72983 0.75884 0.78549 0.80720 0.82618 0.84331
##                           PC15    PC16    PC17    PC18    PC19    PC20    PC21
## Standard deviation     0.91436 0.88840 0.82337 0.78085 0.72968 0.69631 0.65241
## Proportion of Variance 0.01608 0.01518 0.01304 0.01173 0.01024 0.00932 0.00819
## Cumulative Proportion  0.85938 0.87456 0.88760 0.89932 0.90956 0.91889 0.92707
##                           PC22    PC23    PC24    PC25    PC26    PC27    PC28
## Standard deviation     0.63134 0.61862 0.58250 0.55471 0.54126 0.50596 0.48606
## Proportion of Variance 0.00767 0.00736 0.00653 0.00592 0.00563 0.00492 0.00454
## Cumulative Proportion  0.93474 0.94210 0.94862 0.95454 0.96017 0.96510 0.96964
##                           PC29    PC30    PC31    PC32    PC33    PC34    PC35
## Standard deviation     0.45105 0.42413 0.41245 0.36296 0.34904 0.33533 0.30328
## Proportion of Variance 0.00391 0.00346 0.00327 0.00253 0.00234 0.00216 0.00177
## Cumulative Proportion  0.97355 0.97701 0.98028 0.98282 0.98516 0.98732 0.98909
##                           PC36    PC37    PC38    PC39    PC40    PC41    PC42
## Standard deviation     0.28235 0.25340 0.23778 0.23492 0.20199 0.19520 0.18830
## Proportion of Variance 0.00153 0.00123 0.00109 0.00106 0.00078 0.00073 0.00068
## Cumulative Proportion  0.99062 0.99186 0.99295 0.99401 0.99479 0.99553 0.99621
##                           PC43    PC44    PC45    PC46    PC47   PC48    PC49
## Standard deviation     0.18365 0.17949 0.16946 0.16387 0.14718 0.1435 0.11607
## Proportion of Variance 0.00065 0.00062 0.00055 0.00052 0.00042 0.0004 0.00026
## Cumulative Proportion  0.99686 0.99748 0.99803 0.99854 0.99896 0.9994 0.99962
##                           PC50    PC51    PC52
## Standard deviation     0.10897 0.07721 0.04636
## Proportion of Variance 0.00023 0.00011 0.00004
## Cumulative Proportion  0.99984 0.99996 1.00000
#new_features <- predict(pca, newdata = df_norm) #No es necesario volver a ejecutar esta línea, es solo informativa

pca.dat <- as.data.frame(cbind(new_features, group=Mclust.result$classification))

Visualizamos los datos. Para añadir interactividad a los gráficos, usamos la biblioteca ggplotly, que nos permite acceder a información adicional al posicionarnos sobre un punto de interés.

gg2 <- ggplot(pca.dat) +
  geom_point(aes(x=PC1, y=PC2, col=factor(group), text=rownames(pca.dat)), size=2) +
  labs(title = "Visualizing K-Means Clusters Against First Two Principal Components") +
  scale_color_brewer(name="", palette = "Set1")
## Warning: Ignoring unknown aesthetics: text
ggplotly(gg2, tooltip = c("text", "x", "y")) %>%
  layout(legend = list(x=.9, y=.99))

Como era de esperar, el número de clústers es muy elevado y varios clúster solapan entre sí.

Podemos incluso representar los datos en 3D, utilizando las tres primeras componentes principales, que proporcionan algo más del 40% de la información del conjunto.

fig <- plot_ly(x= pca.dat$PC1, y= pca.dat$PC2 , z= pca.dat$PC3, type="scatter3d", mode="markers", color=factor(pca.dat$group), colors=c('red2', 'blue2', 'green3', 'magenta3', 'orange', 'yellow', 'brown2', 'pink', 'gray'))

fig <- fig %>% layout(title = 'Visualizing K-Means Clusters Against First Three Principal Components',
  scene = list(xaxis = list(title = 'PC1'), yaxis = list(title = 'PC2'), zaxis = list(title = 'PC3')))

fig

La visualización en 3D permite estudiar más detalles y observar mejor la frontera entre clústers. Observamos que los clústers 5 y 6 (naranja y amarillo) están bien diferenciados. Sin embargo, los demás se entremezclan en dos grandes grupos.

Por otro lado, es interesante observar que, mientras que el clustering basado en centroides (k-means) estimaba un número óptimo de clústers igual a 3, EM no funciona muy bien sobre este número de clústers.

Podemos estudiar los resultados de EM si fijamos el número de clústers igual a 3:

Mclust.result <- Mclust(df_norm, G=3)

Representamos la gráfica de evolución del BIC (Bayesian Information Criterion) para ver qué modelo se ajusta mejor.

# Notar que la interpretación del BIC en R es al revés de la interp. en Python
## En R: el más positvo, en Python el más negativo
plot(Mclust.result, data=df_norm, what="BIC")

summary(Mclust.result$BIC)
## Best BIC values:
##            VEV,3     EEV,3     EEE,3
## BIC      3573457 3391105.1 3046333.6
## BIC diff       0 -182352.3 -527123.8

De nuevo, el mejor modelo es VEV (distribución elipsoidal, volumen variable, misma forma, orientación variable), esta vez con 3 clúster porque así lo hemos forzado.

Aplicamos PCA

#new_features <- predict(pca, newdata = df_norm) #No es necesario volver a ejecutar esta línea, es solo informativa

pca.dat <- as.data.frame(cbind(new_features, group=Mclust.result$classification))

Visualizamos los datos. Para añadir interactividad a los gráficos, usamos la biblioteca ggplotly, que nos permite acceder a información adicional al posicionarnos sobre un punto de interés.

gg2 <- ggplot(pca.dat) +
  geom_point(aes(x=PC1, y=PC2, col=factor(group), text=rownames(pca.dat)), size=2) +
  labs(title = "Visualizing K-Means Clusters Against First Two Principal Components") +
  scale_color_brewer(name="", palette = "Set1")
## Warning: Ignoring unknown aesthetics: text
ggplotly(gg2, tooltip = c("text", "x", "y")) %>%
  layout(legend = list(x=.9, y=.99))

Representamos los datos en 3D, utilizando las tres primeras componentes principales, que proporcionan algo más del 40% de la información del conjunto.

fig <- plot_ly(x= pca.dat$PC1, y= pca.dat$PC2 , z= pca.dat$PC3, type="scatter3d", mode="markers", color=factor(pca.dat$group), colors=c('red2', 'blue2', 'green3'))

fig <- fig %>% layout(title = 'Visualizing K-Means Clusters Against First Three Principal Components',
  scene = list(xaxis = list(title = 'PC1'), yaxis = list(title = 'PC2'), zaxis = list(title = 'PC3')))

fig

Concluimos que los resultados de EM para k=3 no son muy buenos, como vimos al estudiar el BIC de modelos con entre 1 a 9 clústers.

Modelos con un número mayor de clústers funcionarán mejor, según el BIC, aunque estudiando el modelo para k=9 vimos que los resultados tampoco eran totalmente satisfactorios.

6.5 DBSCAN (Density-based clustering)

En esta última sección implementamos el clustering basado en densidad (DBSCAN). Este tipo de métodos se basa en la premisa de que los clúster son zonas de alta densidad de puntos separadas por zonas de baja densidad de puntos.

Esto permite que puedan identificar clúster de forma arbitaria y que trabajen bien en presencia de ruido.

Utilizaremos el paquete dbscan para implementar este algoritmo. Primero, debemos escoger los valores para los parámetros MinPts y eps. Habitualmente, se suele probar con varios valores de MinPts y pintar la curva de codo para los k-vecinos de cada punto ordenados y se selecciona eps como la altura a la que se produce un cambio en la pendiente de la curva (aproximadamente, puede ser necesario hacer pequeños ajustes).

Utilizaremos la función kNNdistplot para representar este tipo de curva, que recibe como argumento el dataset y el número de vecinos (k) que queremos probar. Para hacer más fácil la obtención del valor de cambio de pendiente, podemos probar a pintar varias líneas horizontales con la función abline a distintas alturas.

El valor de k, como se ha dicho anteriormente, podemos hacerlo variar, aunque muchas veces se suele escoger el número de variables más una.

Una vez escogido el valor de los parámetros, podemos probar a realizar el clustering y comprobar, mediante su visualización, si los distintos conjuntos de puntos son detectados correctamente.

Procedemos a pintar la curva de codo y a pintar un par de líneas de referencia para intentar ajustar el punto de corte. Nuestro dataset (sin la etiqueta de clase) tiene 52 columnas, por lo que probamos k=52+1

kNNdistplot(df_norm, k = 53)

abline(h=1, col="green")

Seleccionamos el punto de corte y ejecutamos el clustering.

db <- dbscan(df_norm, eps=1, minPts=53)

Mostramos un resumen del objeto devuelto tras hacer el clustering.

str(db)
## List of 3
##  $ cluster: int [1:19622] 1 1 1 1 1 1 1 1 1 1 ...
##  $ eps    : num 1
##  $ minPts : num 53
##  - attr(*, "class")= chr [1:2] "dbscan_fast" "dbscan"

El modelo diferencia 4 clústers:

unique(db$cluster)
## [1] 1 2 3 0

Representamos los resultados, para observar que el clustering captura razonablemente bien la mayoría de los puntos en clusters bien diferenciados.

plot(df_norm[1:5], col=db$cluster+1L)

También podemos llevar a cabo un análisis de componentes principales y usar las dos primeras para visualizar los datos. Utilizamos la descomposición realizada en las secciones anteriores

summary(pca)
## Importance of components:
##                           PC1    PC2     PC3     PC4     PC5     PC6     PC7
## Standard deviation     2.8908 2.8466 2.16241 2.03215 1.91101 1.73308 1.49665
## Proportion of Variance 0.1607 0.1558 0.08992 0.07942 0.07023 0.05776 0.04308
## Cumulative Proportion  0.1607 0.3165 0.40646 0.48587 0.55610 0.61386 0.65694
##                            PC8     PC9    PC10    PC11    PC12    PC13    PC14
## Standard deviation     1.43973 1.31043 1.22834 1.17707 1.06266 0.99331 0.94377
## Proportion of Variance 0.03986 0.03302 0.02902 0.02664 0.02172 0.01897 0.01713
## Cumulative Proportion  0.69680 0.72983 0.75884 0.78549 0.80720 0.82618 0.84331
##                           PC15    PC16    PC17    PC18    PC19    PC20    PC21
## Standard deviation     0.91436 0.88840 0.82337 0.78085 0.72968 0.69631 0.65241
## Proportion of Variance 0.01608 0.01518 0.01304 0.01173 0.01024 0.00932 0.00819
## Cumulative Proportion  0.85938 0.87456 0.88760 0.89932 0.90956 0.91889 0.92707
##                           PC22    PC23    PC24    PC25    PC26    PC27    PC28
## Standard deviation     0.63134 0.61862 0.58250 0.55471 0.54126 0.50596 0.48606
## Proportion of Variance 0.00767 0.00736 0.00653 0.00592 0.00563 0.00492 0.00454
## Cumulative Proportion  0.93474 0.94210 0.94862 0.95454 0.96017 0.96510 0.96964
##                           PC29    PC30    PC31    PC32    PC33    PC34    PC35
## Standard deviation     0.45105 0.42413 0.41245 0.36296 0.34904 0.33533 0.30328
## Proportion of Variance 0.00391 0.00346 0.00327 0.00253 0.00234 0.00216 0.00177
## Cumulative Proportion  0.97355 0.97701 0.98028 0.98282 0.98516 0.98732 0.98909
##                           PC36    PC37    PC38    PC39    PC40    PC41    PC42
## Standard deviation     0.28235 0.25340 0.23778 0.23492 0.20199 0.19520 0.18830
## Proportion of Variance 0.00153 0.00123 0.00109 0.00106 0.00078 0.00073 0.00068
## Cumulative Proportion  0.99062 0.99186 0.99295 0.99401 0.99479 0.99553 0.99621
##                           PC43    PC44    PC45    PC46    PC47   PC48    PC49
## Standard deviation     0.18365 0.17949 0.16946 0.16387 0.14718 0.1435 0.11607
## Proportion of Variance 0.00065 0.00062 0.00055 0.00052 0.00042 0.0004 0.00026
## Cumulative Proportion  0.99686 0.99748 0.99803 0.99854 0.99896 0.9994 0.99962
##                           PC50    PC51    PC52
## Standard deviation     0.10897 0.07721 0.04636
## Proportion of Variance 0.00023 0.00011 0.00004
## Cumulative Proportion  0.99984 0.99996 1.00000
#new_features <- predict(pca, newdata = df_norm) #No es necesario volver a ejecutar esta línea, es solo informativa

pca.dat <- as.data.frame(cbind(new_features, group=db$cluster))

Visualizamos los datos. Para añadir interactividad a los gráficos, usamos la biblioteca ggplotly, que nos permite acceder a información adicional al posicionarnos sobre un punto de interés.

gg2 <- ggplot(pca.dat) +
  geom_point(aes(x=PC1, y=PC2, col=factor(group), text=rownames(pca.dat)), size=2) +
  labs(title = "Visualizing K-Means Clusters Against First Two Principal Components") +
  scale_color_brewer(name="", palette = "Set1")
## Warning: Ignoring unknown aesthetics: text
ggplotly(gg2, tooltip = c("text", "x", "y")) %>%
  layout(legend = list(x=.9, y=.99))

Observamos que la mayoría de puntos están asignados a los clústers 1, 2 y 3; que están bien diferenciados. El clúster 0 parece estar formado por muy pocos puntos, que en ocasiones se entremezclan con los puntos de otros clústers.

Representamos los datos en 3D, utilizando las tres primeras componentes principales, que proporcionan algo más del 40% de la información del conjunto.

fig <- plot_ly(x= pca.dat$PC1, y= pca.dat$PC2 , z= pca.dat$PC3, type="scatter3d", mode="markers", color=factor(pca.dat$group), colors=c('red2', 'blue2', 'green3'))

fig <- fig %>% layout(title = 'Visualizing K-Means Clusters Against First Three Principal Components',
  scene = list(xaxis = list(title = 'PC1'), yaxis = list(title = 'PC2'), zaxis = list(title = 'PC3')))

fig

Efectivamente, confirmamos que el clúster 0 no está bien diferenciado de los demás grupos.

Volvamos a la curva de codo de los k-vecinos. Seleccionamos un punto de corte ligeramente mayor, eps= 1.05, y ejecutamos el clustering.

db <- dbscan(df_norm, eps=1.05, minPts=53)

Mostramos un resumen del objeto devuelto tras hacer el clustering.

str(db)
## List of 3
##  $ cluster: int [1:19622] 1 1 1 1 1 1 1 1 1 1 ...
##  $ eps    : num 1.05
##  $ minPts : num 53
##  - attr(*, "class")= chr [1:2] "dbscan_fast" "dbscan"

De nuevo, el modelo diferencia 4 clústers:

unique(db$cluster)
## [1] 1 2 3 0

Llevamos a cabo un análisis de componentes principales y usamos las dos primeras para visualizar los datos. Utilizamos la descomposición realizada en las secciones anteriores.

#new_features <- predict(pca, newdata = df_norm) #No es necesario volver a ejecutar esta línea, es solo informativa

pca.dat <- as.data.frame(cbind(new_features, group=db$cluster))

Visualizamos los datos. Para añadir interactividad a los gráficos, usamos la biblioteca ggplotly, que nos permite acceder a información adicional al posicionarnos sobre un punto de interés.

gg2 <- ggplot(pca.dat) +
  geom_point(aes(x=PC1, y=PC2, col=factor(group), text=rownames(pca.dat)), size=2) +
  labs(title = "Visualizing K-Means Clusters Against First Two Principal Components") +
  scale_color_brewer(name="", palette = "Set1")
## Warning: Ignoring unknown aesthetics: text
ggplotly(gg2, tooltip = c("text", "x", "y")) %>%
  layout(legend = list(x=.9, y=.99))

Podemos representar los datos en 3D, utilizando las tres primeras componentes principales, que proporcionan algo más del 40% de la información del conjunto.

fig <- plot_ly(x= pca.dat$PC1, y= pca.dat$PC2 , z= pca.dat$PC3, type="scatter3d", mode="markers", color=factor(pca.dat$group), colors=c('red2', 'blue2', 'green3'))

fig <- fig %>% layout(title = 'Visualizing K-Means Clusters Against First Three Principal Components',
  scene = list(xaxis = list(title = 'PC1'), yaxis = list(title = 'PC2'), zaxis = list(title = 'PC3')))

fig

Los resultados mejoran apreciablemente.

Los clúster 1, 2 y 3 siguen estando bien diferenciados, mientras que el clúster 0 está ahora mejor definido. En la proyección sobre las tres primeras componentes principales, el clúster 0 solamente se mezcla con el clúster 1, y observamos que incluye puntos atípicos y puntos situados entre clústers.

7 Conclusión

En este análisis hemos utilizado técnicas no supervisadas para construir y evaluar modelos de segmentación que intenten capturar la estructura de grupos existentes en el conjunto de datos estudiado.

En particular, hemos explorado los siguientes modelos:

  • Clustering Jerárquico (agglomerative clustering)
  • Clustering con K-means (centroid-based clustering)
  • Clustering con K-medoids (medoid-based clustering)
  • Expectation-Maximization (distribution-based clustering)
  • DBSCAN (Density-based clustering)

Hemos analizado los resultados de cada modelo utilizando técnicas visuales (representación gráfica de índices de calidad del modelo, visualización de los clusters sobre las variables originales, reducción de dimensionalidad y proyección sobre componentes principales) y cuantitativas (cálculo y comparación de índices de calidad del modelo, evaluación contra etiquetas supervisadas).

El modelo K-means con 3 clústers ha sido el que mejores resultados ha dado, y por tanto el que implementaríamos en un caso real.

El modelo DBSCAN con eps=1.05 y minPts=53 también ha producido buenos resultados. El modelo ha identificado cuatro clústers, tres de ellos bien definidos y con una alta densidad de puntos y uno de ellos formado por un bajo número de puntos que, en ocasiones, se mezcla con otros clústers.

Los modelos K-medoids y EM no han producido buenos resultados. Estos modelos han sido explorados utilizando distintos parámetros. En todos los casos estudiados, la evaluación de sus resultados no fue favorable.

Por último, los modelos aglomerativos de clustering han sido utilizados para explorar los datos y analizar posibles grupos en ellos.

Concluir que, en un análisis real en el que podamos aplicar reglas de negocio o del área específica de estudio, utilizaríamos la información obtenida para caracterizar y segmentar en grupos de interés. Estas técnicas también pueden ser utilizadas para extraer conocimiento de los datos, como fase previa de un análisis supervisado.